c# Substitution Cipher decryption - c#

So I am a teacher and looking to run a little hacking/cryptography club next year.
So I am programming out solutions to a few cryptography methods. I have programmed a randomised substitution cipher but cannot work out the decrypt method with it being random.
I know I need to use letter frequency and pairs of letters of not sure how to program this perfectly.
The sentence I am using is "This is a test of alans cryptography skills"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter the sentence to encrypt");
string plainText = Console.ReadLine();
string cipherText = encrypt(plainText.ToUpper());
Console.WriteLine(cipherText);
Console.ReadLine();
}
public static string encrypt(string phrase)
{
List<string> originalLetters = new List<string>();
//enter the original phrase to the list
for (int i = 0; i < phrase.Length; i++ )
{
originalLetters.Add(phrase[i].ToString());
}
//randomise the subsitutions
//all
List<string> allLetters = new List<string>{"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"};
//shuffled
List<string> shuffledLetters = new List<string>();
int times = allLetters.Count;
Random rng = new Random();
for (int i = 0; i < times;i++ )
{
int position = rng.Next(0, allLetters.Count);
shuffledLetters.Add(allLetters[position]);
Console.Write(allLetters[position] + ", ");
allLetters.RemoveAt(position);
}
Console.WriteLine();
string cipherText = "";
//now change letters into shuffled letters
string SortingLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < originalLetters.Count;i++)
{
//take the original letter
//find its position in the sorting letters
int index = SortingLetters.IndexOf(originalLetters[i]);
//use position to replace to the new string
if (index != -1)
{
//swap the letter with the index plus the key
cipherText += shuffledLetters[index];
}
else
{
cipherText += originalLetters[i];
}
}
//return the encrypted message
return cipherText;
}
public static string decrypt(string phrase)
{
//take the encrypted message
//find most frequent letter as E, focus on single letter words as either I or a
return "finalAnswer";
}
}
}
I have also included example output. I want to keep this hard for my pupils to crack but just using a set key basically makes it a Caesar cipher which I already have a solution for. I have no problem with the program displaying a range of answers that the user has to find the right one from
Any help is appreciated
Thanks

Related

How to go out of bounds back to the start of an array?

I'm making a Caesar cipher, currently I have a shift of three that I want to encrypt the message with. If any letter has "x, y or z" it will give me an out of bounds array error (because the shift is 3).
How can I pass the error by going back to the start of the array, but ending with the remainder of the shift?
This is my code currently:
using System;
using System.Text;
//caesar cipher
namespace Easy47
{
class Program
{
static void Main(string[] args)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var input = Input(alphabet);
Encrypt(3, input, alphabet);
Console.WriteLine();
}
private static void Encrypt(int shift, string input, string alphabet)
{
var message = new StringBuilder();
foreach (char letter in input)
{
for (int i = 0; i < alphabet.Length; i++)
{
if (letter == alphabet[i])
{
message.Append(alphabet[i + shift]);
}
}
}
Console.WriteLine("\n" + message);
}
private static string Input(string alphabet)
{
Console.Write("Input your string\n\n> ");
string input = Console.ReadLine().ToUpper();
return input;
}
}
}
You use the modulo operator:
var i = 255
var z = i % 200 // z == 55
in your case here:
for (int i = 0; i < alphabet.Length; i++)
{
if (letter == alphabet[i])
{
message.Append(alphabet[ (i + shift) % alphabet.Length]);
}
}
If after your addition of shift the index is bigger then alphabet.Length it will start at 0 again.
See C# Ref Modulo Operator
Unrelated, but your loop is not very efficient. A message of "ZZZZZ" would go 5 times through your full alphabet to get translated. You should use a Dictionary as lookup. You can create it at the start before you translate the message and then your lookup is very fast - thats what dictionarys excel at. O(1) lookups :o)
If you know a little about linq, this should be understandable:
// needs: using System.Linq;
private static void Encrypt(int shift, string input, string alphabet)
{
var message = new StringBuilder();
// create a string that is shifted by shift characters
// skip: skips n characters, take: takes n characters
// string.Join reassables the string from the enumerable of chars
var moved = string.Join("",alphabet.Skip(shift))+string.Join("",alphabet.Take(shift));
// the select iterates through your alphabet, c is the character you currently handle,
// i is the index it is at inside of alphabet
// the rest is a fancy way of creating a dictionary for
// a->d
// b->e
// etc using alphabet and the shifted lookup-string we created above.
var lookup = alphabet
.Select( (c,i)=> new {Orig=c,Chiff=moved[i]})
.ToDictionary(k => k.Orig, v => v.Chiff);
foreach (char letter in input)
{
// if the letter is not inside your alphabet, you might want to add
// it "as-is" in a else-branch. (Numbers or dates or .-,?! f.e.)
if (lookup.ContainsKey(letter))
{
message.Append(lookup[letter]);
}
}
Console.WriteLine("\n" + message);
}

Converting Character to Ascii

I've been creating a code breaking software and I need to convert the characters from a text file into ascii numbers to allow the shift. I have left my code below but could someone explain how I could do this?
using System;
using System.IO;
namespace CipherDecoder
{
class Program
{
static void Main(string[] args)
{
string fileText = #"C:/Users/Samuel/Documents/Computer_Science/PaDS/caeserShiftEncodedText";
string cipherText = File.ReadAllText(fileText);
string output = #"C:\\Users\Samuel\Documents\Computer_Science\PaDS\output.txt\";
char[] cipherChars = new char[691];
int j = 0;
foreach (char s in cipherText)
{
cipherChars[j] = s;
j++;
}
for(int i = 0; i < cipherChars.Length; i++)
{
cipherChars[i] = cipherChars[i];
}
}
}
}
To get the int values into an int array you could just do this with as a LINQ select. For example:
string fileText = #"C:/Users/Samuel/Documents/Computer_Science/PaDS/caeserShiftEncodedText";
int [] charactersAsInts = File.ReadAllText(fileText).Select(chr => (int)chr).ToArray();
You can,
var asciiNumbersArray = cipherText.Cast<int>().ToArray();
If you cast a char to int you get the ascii number in decimal system.

Reverse a char array in C#

I am trying to learn C#. I want to enter some text and for it to come out reversed. It reverses it, but multiple times, as many times as the inputted text is long. So hello comes out as olleholleholleholleholleh.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Reversed_Array
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter text to be reversed");
string inputText = Console.ReadLine();
char[] myChar = inputText.ToCharArray();
Array.Reverse(myChar);
foreach (char character in myChar)
{
Console.Write(myChar);
}
Console.ReadLine();
}
}
}
I wanted to experiment with converting a string into a char array. Thought I would note this because yes I don't need the char array.
Because every time you write the whole array not a single character, try this:
foreach (char character in myChar)
{
Console.Write(character);
}
for( int i = myChar.Length -1 ; i >= 0 ; --i )
{
Console.Write(myChar[i]);
}
There's no need to have a special array, do a reverse etc., just print out characters backward:
static void Main(string[] args)
{
Console.WriteLine("Enter text to be reversed");
string inputText = Console.ReadLine();
// Backward loop
for (int i = inputText.Length - 1; i >= 0; --i)
Console.Write(inputText[i]);
}

Random string with no duplicates

I'm trying to generate a 16 chars random string with NO DUPLICATE CHARS. I thoght that it shouldn't be to hard but I'm stuck.
I'm using 2 methods, one to generate key and another to remove duplicate chars. In main I've created a while loop to make sure that generated string is 16 chars long.
There is something wrong with my logic because it just shoots up 16-char string
with duplicates. Just can't get it right.
The code:
public string RemoveDuplicates(string s)
{
string newString = string.Empty;
List<char> found = new List<char>();
foreach (char c in s)
{
if (found.Contains(c))
continue;
newString += c.ToString();
found.Add(c);
}
return newString;
}
public static string GetUniqueKey(int maxSize)
{
char[] chars = new char[62];
chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
byte[] data = new byte[1];
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
crypto.GetNonZeroBytes(data);
data = new byte[maxSize];
crypto.GetNonZeroBytes(data);
StringBuilder result = new StringBuilder(maxSize);
foreach (byte b in data)
{
result.Append(chars[b % (chars.Length)]);
}
return result.ToString();
}
string builder = "";
do
{
builder = GetUniqueKey(16);
RemoveDuplicates(builder);
lblDir.Text = builder;
Application.DoEvents();
} while (builder.Length != 16);
Consider implementing shuffle algorithm with which you will shuffle your string with unique characters and then just pick up first 16 characters.
You can do this in-place, by allocating single StringBuffer which will contain your initial data ("abc....") and just use Durstenfeld's version of the algorithm to mutate your buffer, than return first 16 chars.
There are many algorithms for this.
One easy one is:
Fill an array of chars with the available chars.
Shuffle the array.
Take the first N items (where N is the number of characters you need).
Sample code:
using System;
namespace ConsoleApplication2
{
internal class Program
{
private static void Main(string[] args)
{
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
Random rng = new Random();
for (int i = 0; i < 10; ++i)
{
string randomString = RandomString(16, chars, rng);
Console.WriteLine(randomString);
}
}
public static string RandomString(int n, char[] chars, Random rng)
{
Shuffle(chars, rng);
return new string(chars, 0, n);
}
public static void Shuffle(char[] array, Random rng)
{
for (int n = array.Length; n > 1; )
{
int k = rng.Next(n);
--n;
char temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
}
}
const string chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
var r = new Random();
var s = new string(chars.OrderBy(x => r.Next()).Take(16).ToArray());
I am using a GUID generation method it itself generates random strings and you can modify it if a number appears in the beginning,
use the code given below:
string guid = System.Guid.NewGuid().ToString("N");
while (char.IsDigit(guid[0]))
guid = System.Guid.NewGuid().ToString("N");
Hope that helps.
See if this helps:
RandomString()
{
string randomStr = Guid.NewGuid().ToString();
randomStr = randomStr.Replace("-", "").Substring(0, 16);
Console.WriteLine(randomStr);
}
This returns alpha-numeric string.

Generate password using a for loop

I am making a password generator that generates a random number, then I have it converted to a letter using ascii. Inside the for loop, I need the letters to convert a string instead of a list. It works, but it just displays random letters as a list.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
class MainClass
{
static void Main()
{
int x = 1;
int length;
string a = "Press any key to continue";
object num;
while (x == 1)
{
Console.WriteLine("How many Characters would you like the Password to be? (Press -1 to Stop)");
length = Convert.ToInt32(Console.ReadLine());
try
{
for (int i = 0; i < length; i++)
{
int num1 = Number();
Int32 ASCII = num1;
num = (char)num1;
if (length > 0)
{
Console.WriteLine(num);
}
}
}
catch
{
Console.WriteLine(a);
}
if (length == -1)
break;
}
}
static Random _r = new Random();
static int Number()
{
return _r.Next(65, 90); // decimal
}
}
StringBuilder sb = new StringBuilder();
for( int i = 0; i < length; i++ )
{
int num1 = Number();
Int32 ASCII = num1;
num = (char)num1;
sb.Append( num );
}
Console.WriteLine( sb.ToString() );
This isn't how I would build a password nor how I would generate random text, but this will give you a string and answer the original question.
As to how I would do this task:
System.Security.Cryptography.RNGCryptoServiceProvider _crypto = new System.Security.Cryptography.RNGCryptoServiceProvider();
byte[] bytes = new byte[8]; // this array can be larger if desired
_crypto.GetBytes( bytes );
ulong randomNumber = (ulong)BitConverter.ToInt64( bytes, 0 );
// convert to a string with the encoding of your choice; I prefer Base 62
For completeness sake, here's a Base62 algorithm which I use. Base62 has the advantage over the more commonly-used Base64 in that it does not include any special characters so it is easy to use in query strings, HTML, and JavaScript (with a few minor caveats). Of course, passwords shouldn't be used in any of those places, and you may want to include special characters to make a password more complex.
Regardless, here is how I convert random numbers to Base62.
private static readonly char[] _base62Characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
public static string ToBase62String( long value )
{
if( value < 0L )
{
throw new ArgumentException( "Number must be zero or greater." );
}
if( value == 0 )
{
return "0";
}
string retVal = "";
while( value > 0 )
{
retVal = _base62Characters[value % 62] + retVal;
value = value / 62;
}
return retVal;
}
Lastly, I want to point out that passwords should very rarely be generated for any purpose, because that means they are being distributed in some form. Passwords should be hashed and salted; password resets should rely on random, expiring security tokens allowing the user a one-time reset. Passwords should never be emailed to a user; passwords should never be stored in plaintext or any reversible format.
For password reset token generation, the code I provided could work nicely because it produces a large, cryptographically random number encoded with a web-safe format. But even a hashed GUID would do the trick in that case.
var sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.Append((char)Number());
}
string password = sb.ToString();
Console.WriteLine(password );
But I would change your Number() method to:
private static char GetRandomChar()
{
return (char)_r.Next(65, 90);
}
and then replace the line inside the loop:
sb.Append(GetRandomChar());
//You have to append the values generated by the RandomNumber in to your password variable
class MainClass
{
static void Main()
{
int x = 1;
int length;
string a = "Press any key to continue";
string num=string.Empty;
while (x == 1)
{
Console.WriteLine("How many Characters would you like the Password to be? (Press -1 to Stop)");
length = Convert.ToInt32(Console.ReadLine());
try
{
for (int i = 0; i < length; i++)
{
int num1 = Number();
Int32 ASCII = num1;
num =num+ ((char)num1);
}
Console.WriteLine(num);
}
catch
{
Console.WriteLine(a);
}
if (length == -1)
break;
}
}
static Random _r = new Random();
static int Number()
{
return _r.Next(65, 90); // decimal
}
}
you can try this one
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PasswordSample
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Generated password: {0}", GeneratePassword(12, true));
}
/// <summary>
/// Generate a random password
/// </summary>
/// <param name="pwdLenght">Password lenght</param>
/// <param name="nonAlphaNumericChars">Indicates if password will include non alpha-numeric</param>
/// <returns>Return a password</returns>
private static String GeneratePassword(int pwdLenght, bool nonAlphaNumericChars)
{
// Allowed characters
String allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
if (nonAlphaNumericChars)
{
// Add non-alphanumeric chars
allowedChars += "-&##%!*$?_";
}
char[] passwordChars = new char[pwdLenght];
Random rnd = new Random();
// Generate a random password
for (int i = 0; i < pwdLenght; i++)
passwordChars[i] = allowedChars[rnd.Next(0, allowedChars.Length)];
return new String(passwordChars);
}
}
}
just define a string at near int x...
like
String Password = "";
and in the if statement appent the keyyword.
if (length > 0)
{
Console.WriteLine(num);
Password+=num
}
I found the following post useful when I had to create a method to generate a random password:
https://stackoverflow.com/a/730352/1015289
However, when I wanted to create a short 'validation' style code which would be emailed to a user to confirm their details, I wanted to restrict the validation code to only 8 characters.
For this I used the following:
string validationCoce = Guid.NewGuid().ToString().Substring(0, 8);
This would be stored in a database which also held the users email, both encrypted before being stored for security purposes.
Both the email and validation code were required to validate the users account.
Hope either of the above help?
Kind Regards, Wayne
use Console.Write() instead of Console.WriteLine() otherwise append to some string and print outside the loop

Categories

Resources