This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace GM.Security.Cryptography | |
{ | |
public class SimpleRectangleCipher | |
{ | |
private const string ALPHABET = "ABCDEFGHIJKLMNOPRSTUVZ"; | |
private const char SPACE_REPLACEMENT = 'Q'; | |
public static void Main() | |
{ | |
string textToEncipher = "This tekst vvill be enciphered."; | |
string textToDecipher = "Ufzfr.iljQijtmfftumosQQQdfuzcje"; | |
CheckAlphabetAndSpaceReplacement(); | |
// encipher | |
if(!string.IsNullOrWhiteSpace(textToEncipher)) { | |
List<string> cipher = Encipher(textToEncipher); | |
Console.WriteLine("Cipher:"); | |
foreach(string line in cipher) { | |
Console.WriteLine(line); | |
} | |
if(textToEncipher != Decipher(cipher)) { | |
throw new Exception($"Something is wrong. '{textToEncipher}' should equal '{Decipher(cipher)}'."); | |
} | |
} | |
// decipher | |
if(!string.IsNullOrWhiteSpace(textToDecipher)) { | |
string secret = Decipher(textToDecipher); | |
Console.WriteLine("Secret:"); | |
Console.WriteLine(secret); | |
if(RemoveNewLines(textToDecipher) != string.Join("", Encipher(secret))) { | |
throw new Exception($"Something is wrong. '{RemoveNewLines(textToDecipher)}' should equal '{string.Join("", Encipher(secret))}'."); | |
} | |
} | |
} | |
private static List<string> Encipher(string text) | |
{ | |
string shiftedText = ShiftLeftRight(text, true); | |
int lines = (int)Math.Ceiling(Math.Sqrt(text.Length)); | |
var result = new List<string>(); | |
for(int i = 0; i < lines; ++i) { | |
string line = ""; | |
for(int j = 0; j < lines + 1; ++j) { | |
int pos = j * lines + i; | |
if(shiftedText.Length <= pos) { | |
continue; | |
} | |
line += shiftedText[pos]; | |
} | |
result.Add(line); | |
} | |
return result; | |
} | |
private static string Decipher(List<string> cipher) | |
{ | |
return Decipher(string.Join("", cipher)); | |
} | |
private static string Decipher(string cipher) | |
{ | |
var shiftedCipher = ShiftLeftRight(RemoveNewLines(cipher), false); | |
int lines = (int)Math.Ceiling(Math.Sqrt(shiftedCipher.Length)); | |
int lineLength = (int)Math.Ceiling(shiftedCipher.Length / (double)lines); | |
int fullLengthLines = lines - (lines * lineLength - shiftedCipher.Length); | |
string result = ""; | |
for(int i = 0; i < lineLength; ++i) { | |
for(int j = 0; j < lines; ++j) { | |
if(i == lineLength - 1 && j == fullLengthLines) { | |
break; | |
} | |
int pos = 0; | |
for(int k = 1; k <= j; ++k) { | |
pos += lineLength - (k > fullLengthLines ? 1 : 0); | |
} | |
pos += i; | |
if(shiftedCipher.Length <= pos) { | |
continue; | |
} | |
result += shiftedCipher[pos]; | |
} | |
} | |
return result; | |
} | |
private static string ShiftLeftRight(string text, bool directionRight) | |
{ | |
string shiftedText = ""; | |
for(int i = 0; i < text.Length; ++i) { | |
char c = text[i]; | |
char shiftedC; | |
if(char.IsDigit(c)) { | |
shiftedC = c; | |
} else { | |
int pos = ALPHABET.IndexOf(char.ToUpperInvariant(c)); | |
if(pos == -1 || char.ToUpper(c) == SPACE_REPLACEMENT) { | |
if(!char.IsLetter(c) || char.ToUpper(c) == SPACE_REPLACEMENT) { | |
switch(char.ToUpper(c)) { | |
case ' ': | |
shiftedC = SPACE_REPLACEMENT; | |
break; | |
case SPACE_REPLACEMENT: | |
shiftedC = ' '; | |
break; | |
case '.': | |
case ',': | |
case '-': | |
shiftedC = c; | |
break; | |
default: | |
throw new Exception($"A character that is not allowed: '{c}'."); | |
} | |
} else { | |
throw new Exception($"A letter that is not in the alphabet: '{c}'."); | |
} | |
} else { | |
int shiftedPos = (pos + (directionRight ? 1 : -1) + ALPHABET.Length) % ALPHABET.Length; | |
shiftedC = ALPHABET[shiftedPos]; | |
if(char.IsLower(c)) { | |
shiftedC = char.ToLower(shiftedC); | |
} | |
} | |
} | |
shiftedText += shiftedC; | |
} | |
return shiftedText; | |
} | |
private static string RemoveNewLines(string text) | |
{ | |
return text.Replace("\r", "").Replace("\n", ""); | |
} | |
private static void CheckAlphabetAndSpaceReplacement() | |
{ | |
if(ALPHABET.Any(c => !char.IsLetter(c) || !char.IsUpper(c))) { | |
throw new Exception("All characters in the alphabet must be uppercase letters."); | |
} | |
if(!char.IsUpper(SPACE_REPLACEMENT)) { | |
throw new Exception("The space replacement character must be upper case."); | |
} | |
if(ALPHABET.Any(c => c == char.ToUpper(SPACE_REPLACEMENT))) { | |
throw new Exception("The space replacement character must not be in the alphabet."); | |
} | |
if(SPACE_REPLACEMENT == ',' || SPACE_REPLACEMENT == '.' || SPACE_REPLACEMENT == '-') { | |
throw new Exception("The space replacement character must not be ',', '.' or '-'."); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment