Jump to content

Windows form c#, encryption and adding additional character

Go to solution Solved by Razhan,

 

How do I implement a seed in such a way that the key uses the seed to encrypt and decrypt. 

For example:

Key = {3, 2, 4, 9, 5, 8, 1, 7};
aaa = 2yyy
 
This means that every time the password is encrypted it uses different keys based on the seed.
 
static private List<char> Charset =            new List<char>("PQOWIEURYTLAKSJDHFGMZNXBCV"                + "olpikmujnyhbtgvrfcedxwszaq"                + "1597362480"                + "~!@#$%^&*()_+"                + "PQOWIEURYTLAKSJDHFGMZNXBCV"                + "olpikmujnyhbtgvrfcedxwszaq"                + "1597362480"                + "~!@#$%^&*()_+");       static List<int> Key = new List<int>()       {3,7,2,8,9,12,45,24,35,46,74,56,82,12,34,22,72,       };        static public string Encrypt(string plain, int iv = 55)        {            string cipher = "";            int key = iv % 75;            foreach (char i in plain)            {                key += Charset.IndexOf(i);                key %= 75;                cipher += Charset.ElementAt(key);            }            return cipher;        }        static public string Decrypt(string cipher, int iv = 55)        {            string plain = "";            int key = iv % 75;            int oldkey = 0;            foreach (char i in cipher)            {                oldkey = key;                key = Charset.LastIndexOf(i);                plain += Charset.ElementAt((key + 75 - oldkey) % 75);            }            return plain;        }    }
 

I've put in this code as the seed:

static List<int> Key = new List<int>()       {3,7,2,8,9,12,45,24,35,46,74,56,82,12,34,22,72,       };

This is a very simple cipher algorithm, so you have limited options. The real "key" is somehow the permutation of characters you have in the Charset. However, you could use the InitializationVector as some sort of key. A password encrypted with this algorithm and a specific iv will only be decrypted using that same iv.

 

Bear in mind the iv range is limited to exactly 75 numers (the range from 0 to 74), any IV higher than that is redundant (the iv 75 is equal to 0, 76 to 1...)

 

The code is already prepared to use different ivs. By default, if you call Encrypt(string) it will encrypt the code using 55 as the iv, but you can call Encrypt(string, int) to use a different IV.

 

For example:

string encrypted = Encrypt("Password", 24);

To decrypt this, you will need to call:

string decrypted = Decrypt(decrypted, 24);

Calling:

string decrypted = Decrypt(decrypted);

Will generate garbarge (most likely, never tried)

 

Is this what you were looking for? Using a "random" key is not really a good option, as you need to know which one is used to decrypt the password

 

PS: If you really, really want to have a seed to dictate the key we are going to use, you could do something like (I do not have access to VisualStudio right now, there may be some stupid mistakes in the code):

public static int GetKey(string seed){  Random rdgen = new Random(seed.GetHashCode());  return rdgen.NextInt(75);} public static int GetKey(int seed){  Random rdgen = new Random(seed);  return rdgen.NextInt(75);}

 

You could call this GetKey() method to choose a key between 0 and 74 based on a string or int seed. The method will choose the same key for the same seed, but as the whole domain for keys is only 75... well, there are going to be a lot of collisions

How do I encrypt passwords in such a way that it not only changes the characters of the password but also add extra characters. For example a password as "ABC" would become "12345" instead of "123". Another way is that for each character, the key shift is different. Below are my codes.

class CipherMachine{    static private List<char> Charset =       new List<char>("PQOWIEURYTLAKSJDHFGMZNXBCV"           + "olpikmujnyhbtgvrfcedxwszaq"           + "1597362480"           + "~!@#$%^&*()_+"           + "PQOWIEURYTLAKSJDHFGMZNXBCV"           + "olpikmujnyhbtgvrfcedxwszaq"           + "1597362480"           + "~!@#$%^&*()_+");   static private int Key = 39;   static public string Encrypt(string plain)   {       string cipher = "";       foreach (char i in plain)       {         cipher += Charset.ElementAt(Charset.IndexOf(i) + Key);       }        return cipher;   }   static public string Decrypt(string cipher)   {     string plain = "";     foreach (char i in cipher)   {     plain += Charset.ElementAt(Charset.LastIndexOf(i) - Key);   }   return plain;  } }}

I'm not looking for something too difficult, this is just a small school work and I just want the encryption to be slightly stronger by having the encrypted password to have additional characters compared to the original password used when logging in. 

Link to post
Share on other sites

I don't understand what you're trying to do.

 

Are you trying to create an encryption algorithm, or store passwords? Because if the latter, you should be hashing, not encrypting. And you really shouldn't be rolling your own either way.

Link to post
Share on other sites

I am going to assume this is a school project with absolute no intention to be used in the real world, as this will be extremely insecure 

 

Once that has being said... two thing. I can imagine two reasons you want to store the password:

- Authenticate a user

- Store the password to use it in another place (a "credential manager")

 

If we are in the first use case, you don't need the decrypt function, just store the encrypt password and when the user sends you the password, encrypt it again and compare the encripted version. So, instead of:

- Take ABC -> Encrypt [12345] - Store 12345 -> Receive ABC'  from user -> Decrypt 12345 [ABC] -> Compare ABC' and ABC

- Take ABC -> Encrypt [12345] - Store 12345 -> Receive ABC'  from user -> Encrypt ABC' [12345'] -> Compare 12345 and 12345'

 

Regarding the question, on how to add extra characters, here you have an example. Depending on the input character of the plaintext, it will add 0, 1, 2 or 3 random chars that can be ignored:

            static public string Encrypt(string plain)            {                string cipher = "";                foreach (char i in plain)                {                    int randomNums = Charset.IndexOf(i) % 4;                    cipher += Charset.ElementAt(Charset.IndexOf(i) + Key);                    for (int j = 0; j < randomNums; j++)                    {                        cipher += Charset.ElementAt(rdgen.Next(Charset.Count));                    }                }                return cipher;            }

As I assume this is a school project, I leave to you the decrypt funcion. Also, you will need to be sure rdgen is a Random static object

 

And once more, this will provide no real security. Any algorithm based on the secrecy of the algorithm is considered unsafe in a world with computers

 

Bear in mind that for real world scenarios, C# provides strong crystallographic functions. You can use AES256 for cipher, SHA for hashing and you even have the DPApi (Data Protection API) to easily store information that can only recovered by that specific user (and sadly, malware running as that user :( )

Link to post
Share on other sites

Also, more tips regarding your work (although unsafe, classic cryptography does help to learn modern cryptography)

 

Your algorithm is a Simple Substitution cipher. Substitution because we replace characters in the plain text for other characters to generate the ciphertext. Simple beacuse a single character is processed each time, and will always produce the same character in the ciphertext (i.e. 'P' will always be 'g'). This kind of codes is extremely vulnerable to frequency attacks (e is the most common letter user in English, so the most common letter in the ciphertext has a high chance of being e... and so on)

 

Ways to improve it will be to use a Polyalphabetic solution (Instead of having only one Charset, you have multiple, and you keep changing between them). Easier example, use one charset for odd positions and other one for even positions.

 

Even better solutions, go for a Polygraphic substitution, where the cipher of a character is somehow linked to the other characters in the plaintext.

For example, you alway use a key, value 39. You could use Charset.Index(i-1) as the key. That way, the result of one character will depend on what was the value of the previous character. The only problem will be the first character to cipher, as you cant have Charset.Index(-1), you need to provide a value to start (This is what we call an Initializing Vector, in this case, by default I choose 55, but we can specify a different IV (generating a different ciphertext):

           static public string Encrypt(string plain, int iv = 55)            {                string cipher = "";                int key = iv % 75;                foreach (char i in plain)                {                    key += Charset.IndexOf(i);                    key %= 75;                    cipher += Charset.ElementAt(key);                }                return cipher;            }

 

Before, if we run something like:

string result = CipherMachine.Encrypt("bbbbbbbbbbbb")

We get:

result = "QQQQQQQQQQQQ"

 

Now, if we call something like:

string result = CipherMachine.Encrypt("bbbbbbbbbbbb");

 

We will see that result is:

result = "F9H5D1JqSaKz"

Link to post
Share on other sites

If we are in the first use case, you don't need the decrypt function, just store the encrypt password and when the user sends you the password, encrypt it again and compare the encripted version. So, instead of:

 

- Take ABC -> Encrypt [12345] - Store 12345 -> Receive ABC'  from user -> Encrypt ABC' [12345'] -> Compare 12345 and 12345'

 

Except that's not encryption. It's hashing.

Link to post
Share on other sites

Not sure what you are trying to do, but as said in the following article, don't try to invent your own ways of storing passwords securely, use a way that has been tested thoroughly by experts.

Read the following links and you should get the info you need on how to store passwords hashed and salted properly in C#.

 

http://www.codeproject.com/Articles/704865/Salted-Password-Hashing-Doing-it-Right

 

https://crackstation.net/hashing-security.htm#aspsourcecode

Spoiler

System:

i5 3570k @ 4.4 GHz, MSI Z77A-G43, Dominator Platinum 1600MHz 16GB (2x8GB), EVGA GTX 980ti 6GB, CM HAF XM, Samsung 850 Pro 256GB + Some WD Red HDD, Corsair RM850 80+ Gold, Asus Xonar Essence STX, Windows 10 Pro 64bit

PCPP:

http://pcpartpicker.com/p/znZqcf

 

Link to post
Share on other sites

I am going to assume this is a school project with absolute no intention to be used in the real world, as this will be extremely insecure 

 

Once that has being said... two thing. I can imagine two reasons you want to store the password:

- Authenticate a user

- Store the password to use it in another place (a "credential manager")

 

If we are in the first use case, you don't need the decrypt function, just store the encrypt password and when the user sends you the password, encrypt it again and compare the encripted version. So, instead of:

- Take ABC -> Encrypt [12345] - Store 12345 -> Receive ABC'  from user -> Decrypt 12345 [ABC] -> Compare ABC' and ABC

- Take ABC -> Encrypt [12345] - Store 12345 -> Receive ABC'  from user -> Encrypt ABC' [12345'] -> Compare 12345 and 12345'

 

Regarding the question, on how to add extra characters, here you have an example. Depending on the input character of the plaintext, it will add 0, 1, 2 or 3 random chars that can be ignored:

            static public string Encrypt(string plain)            {                string cipher = "";                foreach (char i in plain)                {                    int randomNums = Charset.IndexOf(i) % 4;                    cipher += Charset.ElementAt(Charset.IndexOf(i) + Key);                    for (int j = 0; j < randomNums; j++)                    {                        cipher += Charset.ElementAt(rdgen.Next(Charset.Count));                    }                }                return cipher;            }

As I assume this is a school project, I leave to you the decrypt funcion. Also, you will need to be sure rdgen is a Random static object

 

And once more, this will provide no real security. Any algorithm based on the secrecy of the algorithm is considered unsafe in a world with computers

 

Bear in mind that for real world scenarios, C# provides strong crystallographic functions. You can use AES256 for cipher, SHA for hashing and you even have the DPApi (Data Protection API) to easily store information that can only recovered by that specific user (and sadly, malware running as that user :( )

You've been a great help man! But 1 more thing, I don't understand by what you said " Also, you will need to be sure rdgen is a Random static object". Care to explain or show example? I'm a total newbie.

Link to post
Share on other sites

Also, more tips regarding your work (although unsafe, classic cryptography does help to learn modern cryptography)

 

Your algorithm is a Simple Substitution cipher. Substitution because we replace characters in the plain text for other characters to generate the ciphertext. Simple beacuse a single character is processed each time, and will always produce the same character in the ciphertext (i.e. 'P' will always be 'g'). This kind of codes is extremely vulnerable to frequency attacks (e is the most common letter user in English, so the most common letter in the ciphertext has a high chance of being e... and so on)

 

Ways to improve it will be to use a Polyalphabetic solution (Instead of having only one Charset, you have multiple, and you keep changing between them). Easier example, use one charset for odd positions and other one for even positions.

 

Even better solutions, go for a Polygraphic substitution, where the cipher of a character is somehow linked to the other characters in the plaintext.

For example, you alway use a key, value 39. You could use Charset.Index(i-1) as the key. That way, the result of one character will depend on what was the value of the previous character. The only problem will be the first character to cipher, as you cant have Charset.Index(-1), you need to provide a value to start (This is what we call an Initializing Vector, in this case, by default I choose 55, but we can specify a different IV (generating a different ciphertext):

           static public string Encrypt(string plain, int iv = 55)            {                string cipher = "";                int key = iv % 75;                foreach (char i in plain)                {                    key += Charset.IndexOf(i);                    key %= 75;                    cipher += Charset.ElementAt(key);                }                return cipher;            }

Before, if we run something like:

string result = CipherMachine.Encrypt("bbbbbbbbbbbb")

We get:

result = "QQQQQQQQQQQQ"

 

Now, if we call something like:

string result = CipherMachine.Encrypt("bbbbbbbbbbbb");

 

We will see that result is:

result = "F9H5D1JqSaKz"

This is close to perfect, just as what I wanted. Having problems with decryption though..

Link to post
Share on other sites

You've been a great help man! But 1 more thing, I don't understand by what you said " Also, you will need to be sure rdgen is a Random static object". Care to explain or show example? I'm a total newbie.

If you put this code in Visual Studio instead of the one you had before, you will see it fails, because at one point we call:

rdgen.Next(Charset.Count)

 

In your code, rdgen does not exists, so the code will fail. rdgen is the name I used for a static variable of type Random. The same way you have:

static private int key

I added:

static private Random rdgen = new Random()
Link to post
Share on other sites

Decryption will be something like:

            static public string Decrypt(string cipher, int iv = 55)            {                string plain = "";                int key = iv % 75;                int oldkey = 0;                foreach (char i in cipher)                {                    oldkey = key;                    key = Charset.LastIndexOf(i);                    plain += Charset.ElementAt((key + 75 - oldkey) % 75);                }                return plain;

Damm, I wrote a large response, but everything after the code disappeared. So quickly:

- Unknown chars are encrypted as + (last char in the Charset)

- You no longer need to repeat the charset twice (Using % 75)

- If this is a shcool project, maybe they suspect the algorithm is not yours

- THIS IS NOT SECURE by any means

- Check @lubblig for real world

Link to post
Share on other sites

Decryption will be something like:

            static public string Decrypt(string cipher, int iv = 55)            {                string plain = "";                int key = iv % 75;                int oldkey = 0;                foreach (char i in cipher)                {                    oldkey = key;                    key = Charset.LastIndexOf(i);                    plain += Charset.ElementAt((key + 75 - oldkey) % 75);                }                return plain;

Damm, I wrote a large response, but everything after the code disappeared. So quickly:

- Unknown chars are encrypted as + (last char in the Charset)

- You no longer need to repeat the charset twice (Using % 75)

- If this is a shcool project, maybe they suspect the algorithm is not yours

- THIS IS NOT SECURE by any means

- Check @lubblig for real world

Sir, by far you are the best! The greatest person who have helped me! Thank you so so much! Yes, indeed this is a school project, but it's weird that my lecturer told me I can get codes from anyone, be it google or somebody who helps with the code as long as I'm able to explain how it works. Once again, thank you!

 

Oh, what does the number '75' represents? In both the encryption and decryption parts

Link to post
Share on other sites

Oh and I'm not allowed to use the advanced method such as hashing, AES256 and DPApi. 

 

Again, I'm struggling to decrypt this

static public string Encrypt(string plain)            {                string cipher = "";                foreach (char i in plain)                {                    int randomNums = Charset.IndexOf(i) % 4;                    cipher += Charset.ElementAt(Charset.IndexOf(i) + Key);                    for (int j = 0; j < randomNums; j++)                    {                        cipher += Charset.ElementAt(rdgen.Next(Charset.Count));                    }                }                return cipher;            }
Link to post
Share on other sites

 

Oh and I'm not allowed to use the advanced method such as hashing, AES256 and DPApi. 

 

Again, I'm struggling to decrypt this

static public string Encrypt(string plain)            {                string cipher = "";                foreach (char i in plain)                {                    int randomNums = Charset.IndexOf(i) % 4;                    cipher += Charset.ElementAt(Charset.IndexOf(i) + Key);                    for (int j = 0; j < randomNums; j++)                    {                        cipher += Charset.ElementAt(rdgen.Next(Charset.Count));                    }                }                return cipher;            }

 

So, basically, the idea here was to add between 0 and 3 random characters after each character in the ciphertext. How many characters are added is something fixed by the char in the plaintext, so we can skip the same amount when decrypting

            static public string Decrypt(string cipher)            {                string plain = "";                int randomNums = 0;                foreach (char i in cipher)                {                    if (randomNums == 0)                    {                        char pchar = Charset.ElementAt((Charset.IndexOf(i) - Key + 75) % 75);                        randomNums = Charset.IndexOf(pchar) % 4;                        plain += pchar;                    }                    else randomNums--;                }                return plain;            }
 
Here you can see how we only decode the char from the ciphertext if randomNums is 0. Also, whenever we decrypt a char, the same way we once calculated how many random chars we had to add:
int randomNums = Charset.IndexOf(i) % 4;
 
We do the same calculation (we have to use an extra variable, pchar, as we are interested of the index of the plain char, not the ciphered one):
                        char pchar = Charset.ElementAt((Charset.IndexOf(i) - Key + 75) % 75);                        randomNums = Charset.IndexOf(pchar) % 4;
I also modified the calculation of the char so it works with a 75 length Charset (by adding 75 (just in case Charset.IndexOf(i) - Key is negative) and then calculating the modulus)
Link to post
Share on other sites

By the way, as final comments (besides the fact this is not secure) that may help you understanding cryptography basics:

 

As I commented before, the main idea of your algorithm was a substitution cipher, where you change the plain text characters into other characters. However, this is not the only technique used, there is also transposition cipher, where you change the position of the characters to make it impossible to read. Both of this techniques has limitations, so in real world, most of the time you are using multiple combinations of both, substitution and transposition.

 

One specific transposition is the concealment, which is your idea of having random characters that are just garbage to confuse people trying to decrypt the cipher. This option is not used a lot of time, mostly because it will increase the size of the ciphertext substantially. However, sometimes, instead of adding "garbage" we find something that is not garbage but where we can conceal an image. The best example of this is a picture.

 

To store a picture we may be using 24 bits to encode the color of each pixel, 8 bits for red, blue and green. One of the 8 bits it really doesn't add so many information to the picture (i.e. 01010101 and 11010101 are almost the same red). So, we can "store" 3 bits in each pixel without altering the picture in a meaningful way. This is an example of steganography, a concealment technique. It can't be considered cryptography, but it is quite cool anyway  :)

Link to post
Share on other sites

By the way, as final comments (besides the fact this is not secure) that may help you understanding cryptography basics:

 

As I commented before, the main idea of your algorithm was a substitution cipher, where you change the plain text characters into other characters. However, this is not the only technique used, there is also transposition cipher, where you change the position of the characters to make it impossible to read. Both of this techniques has limitations, so in real world, most of the time you are using multiple combinations of both, substitution and transposition.

 

One specific transposition is the concealment, which is your idea of having random characters that are just garbage to confuse people trying to decrypt the cipher. This option is not used a lot of time, mostly because it will increase the size of the ciphertext substantially. However, sometimes, instead of adding "garbage" we find something that is not garbage but where we can conceal an image. The best example of this is a picture.

 

To store a picture we may be using 24 bits to encode the color of each pixel, 8 bits for red, blue and green. One of the 8 bits it really doesn't add so many information to the picture (i.e. 01010101 and 11010101 are almost the same red). So, we can "store" 3 bits in each pixel without altering the picture in a meaningful way. This is an example of steganography, a concealment technique. It can't be considered cryptography, but it is quite cool anyway  :)

 

Thanks so much man for all your help although I think I can't thank you enough haha. Your explanations are straightforward, clear and simply awesome! I've seek numerous number of help but you're the only one to provide the perfect answer!  :lol:

Link to post
Share on other sites

Also, more tips regarding your work (although unsafe, classic cryptography does help to learn modern cryptography)

 

Your algorithm is a Simple Substitution cipher. Substitution because we replace characters in the plain text for other characters to generate the ciphertext. Simple beacuse a single character is processed each time, and will always produce the same character in the ciphertext (i.e. 'P' will always be 'g'). This kind of codes is extremely vulnerable to frequency attacks (e is the most common letter user in English, so the most common letter in the ciphertext has a high chance of being e... and so on)

 

Ways to improve it will be to use a Polyalphabetic solution (Instead of having only one Charset, you have multiple, and you keep changing between them). Easier example, use one charset for odd positions and other one for even positions.

 

Even better solutions, go for a Polygraphic substitution, where the cipher of a character is somehow linked to the other characters in the plaintext.

For example, you alway use a key, value 39. You could use Charset.Index(i-1) as the key. That way, the result of one character will depend on what was the value of the previous character. The only problem will be the first character to cipher, as you cant have Charset.Index(-1), you need to provide a value to start (This is what we call an Initializing Vector, in this case, by default I choose 55, but we can specify a different IV (generating a different ciphertext):

           static public string Encrypt(string plain, int iv = 55)            {                string cipher = "";                int key = iv % 75;                foreach (char i in plain)                {                    key += Charset.IndexOf(i);                    key %= 75;                    cipher += Charset.ElementAt(key);                }                return cipher;            }

Before, if we run something like:

string result = CipherMachine.Encrypt("bbbbbbbbbbbb")

We get:

result = "QQQQQQQQQQQQ"

 

Now, if we call something like:

string result = CipherMachine.Encrypt("bbbbbbbbbbbb");

 

We will see that result is:

result = "F9H5D1JqSaKz"

How do I implement a seed in such a way that the key uses the seed to encrypt and decrypt. 

For example:

Key = {3, 2, 4, 9, 5, 8, 1, 7};
aaa = 2yyy
 
This means that every time the password is encrypted it uses different keys based on the seed.
 
static private List<char> Charset =            new List<char>("PQOWIEURYTLAKSJDHFGMZNXBCV"                + "olpikmujnyhbtgvrfcedxwszaq"                + "1597362480"                + "~!@#$%^&*()_+"                + "PQOWIEURYTLAKSJDHFGMZNXBCV"                + "olpikmujnyhbtgvrfcedxwszaq"                + "1597362480"                + "~!@#$%^&*()_+");       static List<int> Key = new List<int>()       {3,7,2,8,9,12,45,24,35,46,74,56,82,12,34,22,72,       };        static public string Encrypt(string plain, int iv = 55)        {            string cipher = "";            int key = iv % 75;            foreach (char i in plain)            {                key += Charset.IndexOf(i);                key %= 75;                cipher += Charset.ElementAt(key);            }            return cipher;        }        static public string Decrypt(string cipher, int iv = 55)        {            string plain = "";            int key = iv % 75;            int oldkey = 0;            foreach (char i in cipher)            {                oldkey = key;                key = Charset.LastIndexOf(i);                plain += Charset.ElementAt((key + 75 - oldkey) % 75);            }            return plain;        }    }
 

I've put in this code as the seed:

static List<int> Key = new List<int>()       {3,7,2,8,9,12,45,24,35,46,74,56,82,12,34,22,72,       };
Link to post
Share on other sites

 

How do I implement a seed in such a way that the key uses the seed to encrypt and decrypt. 

For example:

Key = {3, 2, 4, 9, 5, 8, 1, 7};
aaa = 2yyy
 
This means that every time the password is encrypted it uses different keys based on the seed.
 
static private List<char> Charset =            new List<char>("PQOWIEURYTLAKSJDHFGMZNXBCV"                + "olpikmujnyhbtgvrfcedxwszaq"                + "1597362480"                + "~!@#$%^&*()_+"                + "PQOWIEURYTLAKSJDHFGMZNXBCV"                + "olpikmujnyhbtgvrfcedxwszaq"                + "1597362480"                + "~!@#$%^&*()_+");       static List<int> Key = new List<int>()       {3,7,2,8,9,12,45,24,35,46,74,56,82,12,34,22,72,       };        static public string Encrypt(string plain, int iv = 55)        {            string cipher = "";            int key = iv % 75;            foreach (char i in plain)            {                key += Charset.IndexOf(i);                key %= 75;                cipher += Charset.ElementAt(key);            }            return cipher;        }        static public string Decrypt(string cipher, int iv = 55)        {            string plain = "";            int key = iv % 75;            int oldkey = 0;            foreach (char i in cipher)            {                oldkey = key;                key = Charset.LastIndexOf(i);                plain += Charset.ElementAt((key + 75 - oldkey) % 75);            }            return plain;        }    }
 

I've put in this code as the seed:

static List<int> Key = new List<int>()       {3,7,2,8,9,12,45,24,35,46,74,56,82,12,34,22,72,       };

This is a very simple cipher algorithm, so you have limited options. The real "key" is somehow the permutation of characters you have in the Charset. However, you could use the InitializationVector as some sort of key. A password encrypted with this algorithm and a specific iv will only be decrypted using that same iv.

 

Bear in mind the iv range is limited to exactly 75 numers (the range from 0 to 74), any IV higher than that is redundant (the iv 75 is equal to 0, 76 to 1...)

 

The code is already prepared to use different ivs. By default, if you call Encrypt(string) it will encrypt the code using 55 as the iv, but you can call Encrypt(string, int) to use a different IV.

 

For example:

string encrypted = Encrypt("Password", 24);

To decrypt this, you will need to call:

string decrypted = Decrypt(decrypted, 24);

Calling:

string decrypted = Decrypt(decrypted);

Will generate garbarge (most likely, never tried)

 

Is this what you were looking for? Using a "random" key is not really a good option, as you need to know which one is used to decrypt the password

 

PS: If you really, really want to have a seed to dictate the key we are going to use, you could do something like (I do not have access to VisualStudio right now, there may be some stupid mistakes in the code):

public static int GetKey(string seed){  Random rdgen = new Random(seed.GetHashCode());  return rdgen.NextInt(75);} public static int GetKey(int seed){  Random rdgen = new Random(seed);  return rdgen.NextInt(75);}

 

You could call this GetKey() method to choose a key between 0 and 74 based on a string or int seed. The method will choose the same key for the same seed, but as the whole domain for keys is only 75... well, there are going to be a lot of collisions

Link to post
Share on other sites

Also, more tips regarding your work (although unsafe, classic cryptography does help to learn modern cryptography)

 

Your algorithm is a Simple Substitution cipher. Substitution because we replace characters in the plain text for other characters to generate the ciphertext. Simple beacuse a single character is processed each time, and will always produce the same character in the ciphertext (i.e. 'P' will always be 'g'). This kind of codes is extremely vulnerable to frequency attacks (e is the most common letter user in English, so the most common letter in the ciphertext has a high chance of being e... and so on)

 

Ways to improve it will be to use a Polyalphabetic solution (Instead of having only one Charset, you have multiple, and you keep changing between them). Easier example, use one charset for odd positions and other one for even positions.

 

Even better solutions, go for a Polygraphic substitution, where the cipher of a character is somehow linked to the other characters in the plaintext.

For example, you alway use a key, value 39. You could use Charset.Index(i-1) as the key. That way, the result of one character will depend on what was the value of the previous character. The only problem will be the first character to cipher, as you cant have Charset.Index(-1), you need to provide a value to start (This is what we call an Initializing Vector, in this case, by default I choose 55, but we can specify a different IV (generating a different ciphertext):

           static public string Encrypt(string plain, int iv = 55)            {                string cipher = "";                int key = iv % 75;                foreach (char i in plain)                {                    key += Charset.IndexOf(i);                    key %= 75;                    cipher += Charset.ElementAt(key);                }                return cipher;            }

Before, if we run something like:

string result = CipherMachine.Encrypt("bbbbbbbbbbbb")

We get:

result = "QQQQQQQQQQQQ"

 

Now, if we call something like:

string result = CipherMachine.Encrypt("bbbbbbbbbbbb");

 

We will see that result is:

result = "F9H5D1JqSaKz"

Why does string result = CipherMachine.Encrypt("bbbbbbbbb")

 

result = "F9H5D1JqS" but,

string result = CipherMachine.Encrypt("aaaaaaaaa")

result = "kE7kE7kE7"

Link to post
Share on other sites

Why does string result = CipherMachine.Encrypt("bbbbbbbbb")

 

result = "F9H5D1JqS" but,

string result = CipherMachine.Encrypt("aaaaaaaaa")

result = "kE7kE7kE7"

Curious, I was aware something like this could happen, although I did not know the chances to happen so soon.

You can call it an armonic, resonance or something similar. This is an extremely simple algorithm, and to calculate the cipher of a character pn, we only take into account the value of pn and the encoding of cn-1. Than means if pn is constant, only one value is taken into account to calculate cn, an that is cn-1. While we keep feeding the algorithm with a constant plaintext, at some point, it will generate a value of cn that is the same as cn-x (x could be any value between 1 and 75), so the value of cn+1 is the same as cn-x+1, and the ciphertext will repeat itself. As there are only 75 possible outputs for a char in the algorithm, at some point the algorithm will start to repeat itself. For "aaaa..." this happens every three chars, but this will also happen for "bbbb..." if the string is long enough:

result = "F9H5D1JqSaKzAsLwTxYdReUcEfIrWvOgQtPb+h_y)n(j*u&m^k%i$p#l@o!V~C0B8X4N2Z6M3G7F9H5D1...."

Did you see how at the end F9H5D1 will start repeating itself?

 

So... our little algorithm is vulnerable to extreme cases of frequency analysis. When attempting to break an algorithm, one of the most potent attacks is called the chosen plaintext attack, where you can feed the encryption function a message to encrypt and see the results. Feeding things like an empty message or a message made of the same character is a common operation, as it reveals weaknesses of the algorithm like you did 

 

So... can we improve the security of our algorithm from none to almost none? Sure. We just need to make the value of cn to depend on something else. For example, the position of cn (stored in the variable count)

            static public string Encrypt(string plain, int iv = 55)            {                string cipher = "";                int key = iv % 75;                int count = 0;                foreach (char i in plain)                {                    key += Charset.IndexOf(i) + count;                    key %= 75;                    cipher += Charset.ElementAt(key);                    count++;                }                return cipher;            }            static public string Decrypt(string cipher, int iv = 55)            {                string plain = "";                int key = iv % 75;                int oldkey = 0;                int count = 0;                foreach (char i in cipher)                {                    oldkey = key;                    key = Charset.LastIndexOf(i);                    int index = (key - oldkey - count) % 75;                    if (index < 0) index += 75;                    plain += Charset.ElementAt(index);                    count++;                }                return plain;            }

Now, if we check the value of encoding a single char string...:

result = "kU2hD*qjHP8xjNLP$2qdvhjmkkmjhvdq2$PLNjx8PHjq*D"
It may look better, but actually the patter will keep repeating (do yo see how there is a simmetry aroung hjmkmjh?)
So maybe not so evident (and now, I think the patter will only start repeating after 75 chars, never as before after 3, although don't quote me on this)
 
The main problem here is generate some randomness, something that will create a sequence that avoids repeating itself. This is quite difficult. I will go further, extremely difficult.
 
Sure, we can do something as:
            static public string Encrypt(string plain, int iv = 55)            {                string cipher = "";                int key = iv % 75;                int count = 0;                foreach (char i in plain)                {                    key += Charset.IndexOf(i) + plain.Substring(0, count).GetHashCode();                     key %= 75;                    if (key < 0) key += 75;                    cipher += Charset.ElementAt(key);                    count++;                }                return cipher;            }            static public string Decrypt(string cipher, int iv = 55)            {                string plain = "";                int key = iv % 75;                int oldkey = 0;                int count = 0;                foreach (char i in cipher)                {                    oldkey = key;                    key = Charset.LastIndexOf(i);                    int index = (key - oldkey - plain.Substring(0, count).GetHashCode()) % 75;                    if (index < 0) index += 75;                    plain += Charset.ElementAt(index);                    count++;                }                return plain;            }
 
 
 
Using the GetHashCode() I haven't been able to find a pattern:
result = "QN6CM5uJII(na_javx^uC9F^bawQmc(ORwuey20B1~1CFWTYDyg7c8J$HbtpgaUh+v&noYzevX(vH*iL2S7qZY4S&1wMg_va5lT$rY*HdV8FrYnRlwK(njv*Gt$p2Nw_qPYynIbb@[member=bzzerc]_"
 
But if we are going to call GetHashCode() we might as well directly call the AES cipher
 
As you can see, cipher algorithms can get nasty really fast
Link to post
Share on other sites

Ok, here it is, one that shouldn't be so vulnerable to frequency attacks withouth calling an internal method like GetHashCode():

        public static int getRand(int number)            {                return ((number * 1103515245) + 12345) & 0x7fffffff;            }             static public string Encrypt(string plain, int iv = 0)            {                StringBuilder cipher = new StringBuilder();                int key = iv % 75;                 for (int i = 0; i < plain.Length; i++)                {                    key += Charset.IndexOf(plain[i]) + getRand(i);                    key %= 75;                    cipher.Append(Charset[key]);                }                 return cipher.ToString();            }            static public string Decrypt(string cipher, int iv = 0)            {                StringBuilder plain = new StringBuilder();                int key = iv % 75;                int index = 0;                for (int i = 0; i < cipher.Length; i++)                {                    index = key;                    key = Charset.IndexOf(cipher[i]);                    index = key - index - getRand(i);                    index = index > 0 ? index % 75 : (index % 75) + 75;                    plain.Append(Charset[index]);                }                 return plain.ToString();            }

This part:

            public static int getRand(int number)            {                return ((number * 1103515245) + 12345) & 0x7fffffff;            }
 
Is part of the glibc implementation of rand. It is called linear congruential generator
 

 

Now, when we cipher something like "aaa...." we get:

result = "ZLXIY65MRvZdFn_Rtg~7*7~gtR_nFdZvRM56Y3+gzUYuofphJJ4qS)oOB$Ige(^KQK^(egI$BOWzfE#Z)M!Ote)*DEF+W1sJOyDvKi^Ojn6a#ln!~Y+K*PawJWbGeFyPLfe^~W@)aaZKzj~t4lF1n0y9Zm@%FKiHVIEqeR%X+N#Ivx+)FRMQEmldjcBV)$kHwVsGj*Omkqf7tc"

 

As you can see, there are some patterns like:

Y65MRvZdFn_Rtg~7*7~gtR_nFdZvRM56Y

 

Or:

OB$Ige(^KQK^(egI$BO

 

But is way better than before

Link to post
Share on other sites

 

Ok, here it is, one that shouldn't be so vulnerable to frequency attacks withouth calling an internal method like GetHashCode():

        public static int getRand(int number)            {                return ((number * 1103515245) + 12345) & 0x7fffffff;            }             static public string Encrypt(string plain, int iv = 0)            {                StringBuilder cipher = new StringBuilder();                int key = iv % 75;                 for (int i = 0; i < plain.Length; i++)                {                    key += Charset.IndexOf(plain[i]) + getRand(i);                    key %= 75;                    cipher.Append(Charset[key]);                }                 return cipher.ToString();            }            static public string Decrypt(string cipher, int iv = 0)            {                StringBuilder plain = new StringBuilder();                int key = iv % 75;                int index = 0;                for (int i = 0; i < cipher.Length; i++)                {                    index = key;                    key = Charset.IndexOf(cipher[i]);                    index = key - index - getRand(i);                    index = index > 0 ? index % 75 : (index % 75) + 75;                    plain.Append(Charset[index]);                }                 return plain.ToString();            }

This part:

            public static int getRand(int number)            {                return ((number * 1103515245) + 12345) & 0x7fffffff;            }
 
Is part of the glibc implementation of rand. It is called linear congruential generator
 

 

Now, when we cipher something like "aaa...." we get:

result = "ZLXIY65MRvZdFn_Rtg~7*7~gtR_nFdZvRM56Y3+gzUYuofphJJ4qS)oOB$Ige(^KQK^(egI$BOWzfE#Z)M!Ote)*DEF+W1sJOyDvKi^Ojn6a#ln!~Y+K*PawJWbGeFyPLfe^~W@)aaZKzj~t4lF1n0y9Zm@%FKiHVIEqeR%X+N#Ivx+)FRMQEmldjcBV)$kHwVsGj*Omkqf7tc"

As you can see, there are some patterns like:

Y65MRvZdFn_Rtg~7*7~gtR_nFdZvRM56Y

Or:

OB$Ige(^KQK^(egI$BO

But is way better than before

 

Thanks again man for everything, once again, superb explanation. So is this the AES method or the previous one where the code contains "GetHashCode" is the AES method? 

Can AES be used on my codes or my codes are too simple?

Link to post
Share on other sites

Thanks again man for everything, once again, superb explanation. So is this the AES method or the previous one where the code contains "GetHashCode" is the AES method? 

Can AES be used on my codes or my codes are too simple?

No, this is not AES, not even close!!!

 

GetHashCode doesn't use AES either, GetHashCode uses a Hashing algorithm (MD5 if I am correct), not an encrypt one. The reason I wanted to avoid calling GetHashCode is because there are complex math operations there, and if you are going to call a System function that perform this kind of operations, why not call AES directly? I tried to keep all the code samples I provided you easy to understand.

 

Using AES in C# is not hard, although is not trivial either (you may need to set the Key, IV, BlockSize...). Internet is full of examples, but I will get you a few keys to understand it:

- AES is a block mode cipher. That means it will block multiple bytes at the same time (128 bytes), not like your cipher that was a stream cipher (one byte/char at a time)

- An example of stream cipher would be RC4, however, C# does not provide an implementation (i think the algorithm was registered and was leaked, something like that. Everyone knows how to implement it, but that doesn't mean you are legally allowed (I do not know the current legal state)

- Aes does not encrypt Strings directly, it encrypts data streams. That's the reason you will see conversions from strings to bytes and then the bytes to streams

- There are two different ways for the code to work. One is to call a .Net function that will perform the encryption. However, Windows offers several Cryptographic services called the CryptoApi (CAPI). If you see they are calling AESManaged, they are using the .NET implementation. If they are using AesCryptoServiceProvider, they are sending the data to windows to be encrypted.

- AES algorithm means (Advanced Encryption Standard). Before becoming AES, the algorithm was called Rjindael. AesManaged and RjindaelManaged are "almost" the same (Rjindael accepts different block sizes)

- Keys are usually 128 or 256 bytes. Usually, one person needs to know the key, so to avoid extra complexity, an extra algorithm is created that derives the key from a string. That way, instead of the key you only need a Password (the code will always use the same function to calculate a key based on the string password)

 

Here is a nice and clean example of calling AESManaged:

http://www.obviex.com/samples/encryption.aspx

 

 

Any doubts you have, just ask

Link to post
Share on other sites

No, this is not AES, not even close!!!

 

GetHashCode doesn't use AES either, GetHashCode uses a Hashing algorithm (MD5 if I am correct), not an encrypt one. The reason I wanted to avoid calling GetHashCode is because there are complex math operations there, and if you are going to call a System function that perform this kind of operations, why not call AES directly? I tried to keep all the code samples I provided you easy to understand.

 

Using AES in C# is not hard, although is not trivial either (you may need to set the Key, IV, BlockSize...). Internet is full of examples, but I will get you a few keys to understand it:

- AES is a block mode cipher. That means it will block multiple bytes at the same time (128 bytes), not like your cipher that was a stream cipher (one byte/char at a time)

- An example of stream cipher would be RC4, however, C# does not provide an implementation (i think the algorithm was registered and was leaked, something like that. Everyone knows how to implement it, but that doesn't mean you are legally allowed (I do not know the current legal state)

- Aes does not encrypt Strings directly, it encrypts data streams. That's the reason you will see conversions from strings to bytes and then the bytes to streams

- There are two different ways for the code to work. One is to call a .Net function that will perform the encryption. However, Windows offers several Cryptographic services called the CryptoApi (CAPI). If you see they are calling AESManaged, they are using the .NET implementation. If they are using AesCryptoServiceProvider, they are sending the data to windows to be encrypted.

- AES algorithm means (Advanced Encryption Standard). Before becoming AES, the algorithm was called Rjindael. AesManaged and RjindaelManaged are "almost" the same (Rjindael accepts different block sizes)

- Keys are usually 128 or 256 bytes. Usually, one person needs to know the key, so to avoid extra complexity, an extra algorithm is created that derives the key from a string. That way, instead of the key you only need a Password (the code will always use the same function to calculate a key based on the string password)

 

Here is a nice and clean example of calling AESManaged:

http://www.obviex.com/samples/encryption.aspx

 

 

Any doubts you have, just ask

Hey man I was trying to do AES on my code, btw it's a windows form. So I did this, I'm able to build but when I debug, visual studio will crash which means there are some problems with the codes I did. Could you provide a sample or correct any mistakes here? Thanks.

 

 class CipherMachine    {        static public string Encrypt    (        string plain = "",        string passPhrase = "Pas5pr@se",        string saltValue = "s@1tValue",        string hashAlgorithm = "SHA1",        int passwordIterations = 2,        string initVector = "@1B2c3D4e5F6g7H8",        int keySize = 256    )        {            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);            byte[] plainTextBytes = Encoding.UTF8.GetBytes(plain);            PasswordDeriveBytes Password = new PasswordDeriveBytes            (                passPhrase,                saltValueBytes,                hashAlgorithm,                passwordIterations            );            byte[] keyBytes = Password.GetBytes(keySize / 8);            RijndaelManaged symmetricKey = new RijndaelManaged();            symmetricKey.Mode = CipherMode.CBC;            ICryptoTransform encryptor = symmetricKey.CreateEncryptor            (                keyBytes,                initVectorBytes            );            MemoryStream memoryStream = new MemoryStream();            CryptoStream cryptoStream = new CryptoStream            (                memoryStream,                encryptor,                CryptoStreamMode.Write            );            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);            cryptoStream.FlushFinalBlock();            byte[] cipherTextBytes = memoryStream.ToArray();            memoryStream.Close();            cryptoStream.Close();            string cipher = Convert.ToBase64String(cipherTextBytes);            return cipher;        }        static public string Decrypt        (            string cipher,            string passPhrase = "Pas5pr@se",            string saltValue = "s@1tValue",            string hashAlgorithm = "SHA1",            int passwordIterations = 2,            string initVector = "@1B2c3D4e5F6g7H8",            int keySize = 256        )        {            byte[] initVectorBytes = Encoding.ASCII.GetBytes(initVector);            byte[] saltValueBytes = Encoding.ASCII.GetBytes(saltValue);            byte[] cipherTextBytes = Convert.FromBase64String(cipher);            PasswordDeriveBytes Password = new PasswordDeriveBytes            (                passPhrase,                saltValueBytes,                hashAlgorithm,                passwordIterations            );            byte[] keyBytes = Password.GetBytes(keySize / 8);            RijndaelManaged symmetricKey = new RijndaelManaged();            symmetricKey.Mode = CipherMode.CBC;            ICryptoTransform decryptor = symmetricKey.CreateDecryptor            (                keyBytes,                initVectorBytes            );            MemoryStream memoryStream = new MemoryStream(cipherTextBytes);            CryptoStream cryptoStream = new CryptoStream            (                memoryStream,                decryptor,                CryptoStreamMode.Read            );            byte[] plainTextBytes = new byte[cipherTextBytes.Length];            int decryptedByteCount = cryptoStream.Read            (                plainTextBytes,                0,                plainTextBytes.Length            );            memoryStream.Close();            cryptoStream.Close();            string plain = Encoding.UTF8.GetString            (                plainTextBytes,                0,                decryptedByteCount            );            return plain;        }    }}

Btw, when doing AESManaged or RijndaelManaged, is it a must to put in this?

using System.IO;using System.Security.Cryptography;

Thanks for all your help!

 

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×