Skip to content

Instantly share code, notes, and snippets.

@Guiorgy
Last active November 12, 2022 23:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Guiorgy/da837e4844d0006fce53800a031c5639 to your computer and use it in GitHub Desktop.
Save Guiorgy/da837e4844d0006fce53800a031c5639 to your computer and use it in GitHub Desktop.
A simple implementation of the Vigenere Cipher in C#
// #define VERBOSE // define for debug logs
// By deafult the alphabet only includes Lowercase Latin letters and the space character
#define INCLUDE_UPPER // define to include Uppercase Latin letters
#define INCLUDE_NUMBERS // define to include numbers
#define INCLUDE_SYMBOLS // define to include other valid ASCII characters
// #define INCLUDE_GEORGIAN // define to include Georgian letters
#define IGNORE_INVALID_CHARACTERS // define to discard invalid characters without stopping the algorithm
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static System.Console;
namespace VigenereCipher
{
public class Program
{
public static void Main(string[] args)
{
const string key = "This is a key!";
const string message = "A super secret message!";
string ciphertext = EncryptVigenere(message, key);
Console.WriteLine($"Cyphertext: {ciphertext}");
string decrypted = DecryptVigenere(ciphertext, key);
Console.WriteLine($"Decrypted: {decrypted}");
}
#region Algorithm
static readonly int AlphabetLength;
static Dictionary<char, byte> Encoder = new Dictionary<char, byte>();
static Dictionary<byte, char> Decoder = new Dictionary<byte, char>();
static Program() {
#if VERBOSE
Console.WriteLine($".NET Runtime version: {typeof(string).Assembly.ImageRuntimeVersion}");
Console.WriteLine();
#endif
byte code = 0;
// Default
Encoder.Add(' ', code);
Decoder.Add(code++, ' ');
for (char c = 'a'; c <= 'z'; ++c) {
Encoder.Add(c, code);
Decoder.Add(code++, c);
}
// Uppercase letters
#if INCLUDE_UPPER
for (char c = 'A'; c <= 'Z'; ++c) {
Encoder.Add(c, code);
Decoder.Add(code++, c);
}
#endif
// Numbers
#if INCLUDE_NUMBERS
for (char c = '0'; c <= '9'; ++c) {
Encoder.Add(c, code);
Decoder.Add(code++, c);
}
#endif
// Other valid ASCII characters
#if INCLUDE_SYMBOLS
for (char c = '!'; c <= '/'; ++c) {
Encoder.Add(c, code);
Decoder.Add(code++, c);
}
for (char c = ':'; c <= '@'; ++c) {
Encoder.Add(c, code);
Decoder.Add(code++, c);
}
for (char c = '['; c <= '`'; ++c) {
Encoder.Add(c, code);
Decoder.Add(code++, c);
}
for (char c = '{'; c <= '~'; ++c) {
Encoder.Add(c, code);
Decoder.Add(code++, c);
}
#endif
// Georgian
#if INCLUDE_GEORGIAN
for (char c = 'ა'; c <= 'ჰ'; ++c) {
Encoder.Add(c, code);
Decoder.Add(code++, c);
}
#endif
AlphabetLength = Encoder.Count();
#if VERBOSE
Console.WriteLine("----- Encoding -----");
foreach (var e in Encoder) Console.WriteLine($"{e.Key}: {e.Value}");
Console.WriteLine();
Console.WriteLine("----- Decoding -----");
foreach (var d in Decoder) Console.WriteLine($"{d.Key}: {d.Value}");
Console.WriteLine();
#endif
}
public static string EncryptVigenere(string message, string key) {
#if VERBOSE
Console.WriteLine("Encrypting (Vigenere):");
Console.WriteLine($"\tMessage: {message}");
Console.WriteLine($"\tKey: {key}");
#endif
#if !INCLUDE_UPPER
message = message.ToLower();
key = key.ToLower();
#endif
#if IGNORE_INVALID_CHARACTERS
message = string.Concat(message.Where(c => Encoder.ContainsKey(c)));
if (message.Length == 0) return "";
key = string.Concat(key.Where(c => Encoder.ContainsKey(c)));
if (key.Length == 0) return "Invalid key!";
#else
if (message.Any(c => !Encoder.ContainsKey(c))) return "Invalid character in message!";
if (key.Any(c => !Encoder.ContainsKey(c))) return "Invalid character in key!";
#endif
#if (VERBOSE && (!INCLUDE_UPPER || IGNORE_INVALID_CHARACTERS))
Console.WriteLine("Sanitized arguments:");
Console.WriteLine($"\tMessage: {message}");
Console.WriteLine($"\tKey: {key}");
#endif
#if VERBOSE
Console.WriteLine();
#endif
StringBuilder ciphertext = new StringBuilder(message.Length);
int k = 0;
foreach (var m in message) {
#if VERBOSE
Console.Write($"{m}({Encoder[m]}) + {key[k]}({Encoder[key[k]]}) mod {AlphabetLength} = ");
Console.WriteLine($"{Decoder[(byte)((Encoder[m] + Encoder[key[k]]) % AlphabetLength)]}({(Encoder[m] + Encoder[key[k]]) % AlphabetLength})");
#endif
ciphertext.Append(Decoder[(byte)((Encoder[m] + Encoder[key[k++]]) % AlphabetLength)]);
if (k == key.Length) k = 0;
}
#if VERBOSE
Console.WriteLine();
#endif
return ciphertext.ToString();
}
public static string DecryptVigenere(string ciphertext, string key) {
#if VERBOSE
Console.WriteLine("Decrypting (Vigenere):");
Console.WriteLine($"\tCiphertext: {ciphertext}");
Console.WriteLine($"\tKey: {key}");
#endif
#if !INCLUDE_UPPER
ciphertext = ciphertext.ToLower();
key = key.ToLower();
#endif
#if IGNORE_INVALID_CHARACTERS
ciphertext = string.Concat(ciphertext.Where(c => Encoder.ContainsKey(c)));
if (ciphertext.Length == 0) return "";
key = string.Concat(key.Where(c => Encoder.ContainsKey(c)));
if (key.Length == 0) return "Invalid key!";
#else
if (ciphertext.Any(c => !Encoder.ContainsKey(c))) return "Invalid character in ciphertext!";
if (key.Any(c => !Encoder.ContainsKey(c))) return "Invalid character in key!";
#endif
#if (VERBOSE && (!INCLUDE_UPPER || IGNORE_INVALID_CHARACTERS))
Console.WriteLine("Sanitized arguments:");
Console.WriteLine($"\tCiphertext: {ciphertext}");
Console.WriteLine($"\tKey: {key}");
#endif
#if VERBOSE
Console.WriteLine();
#endif
StringBuilder decrypted = new StringBuilder(ciphertext.Length);
int k = 0;
foreach (var c in ciphertext) {
#if VERBOSE
Console.Write($"{c}({Encoder[c]}) - {key[k]}({Encoder[key[k]]}) mod {AlphabetLength} = ");
Console.WriteLine($"{Decoder[(byte)((AlphabetLength + Encoder[c] - Encoder[key[k]]) % AlphabetLength)]}({(AlphabetLength + Encoder[c] - Encoder[key[k]]) % AlphabetLength})");
#endif
decrypted.Append(Decoder[(byte)((AlphabetLength + Encoder[c] - Encoder[key[k++]]) % AlphabetLength)]);
if (k == key.Length) k = 0;
}
#if VERBOSE
Console.WriteLine();
#endif
return decrypted.ToString();
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment