Skip to content

Instantly share code, notes, and snippets.

@savaged
Last active July 17, 2023 07:38
Show Gist options
  • Save savaged/fa1d2becbd60e5787c494258686cb72d to your computer and use it in GitHub Desktop.
Save savaged/fa1d2becbd60e5787c494258686cb72d to your computer and use it in GitHub Desktop.
Some fun with ciphers in C#
using System.Text;
App.Run(args, Console.WriteLine);
interface ICipherService
{
string Apply(string input, bool encrypt = false);
}
class XOrCipherService : ICipherService
{
private readonly Encoding _textEncoder;
private readonly byte[] _key;
public XOrCipherService(
string key = "",
Encoding? textEncoder = null)
{
_textEncoder = textEncoder ?? Encoding.ASCII;
_key = _textEncoder.GetBytes(KeyOrDefault(key));
}
public string Apply(string input, bool encrypt = false) =>
EncryptDecrypt(input);
private string EncryptDecrypt(string input) =>
_textEncoder.GetString(EncryptDecrypt(input, _key));
private byte[] EncryptDecrypt(string input, IReadOnlyList<byte> key) =>
EncryptDecrypt(_textEncoder.GetBytes(input), key);
private static byte[] EncryptDecrypt(byte[] input, IReadOnlyList<byte> key, int i = 0)
{
if (i == input.Length)
return input;
input[i] ^= key[i % key.Count];
return EncryptDecrypt(input, key, i + 1);
}
private static string KeyOrDefault(string key) =>
!string.IsNullOrEmpty(key) ? key
: new string(Enumerable.Range(97, 26).Select(i => (char)i).ToArray());
}
class Base64CipherService : ICipherService
{
private readonly Encoding _textEncoder;
public Base64CipherService(Encoding? textEncoder = null) =>
_textEncoder = textEncoder ?? Encoding.ASCII;
public string Apply(string input, bool encrypt = false) =>
encrypt
? Try(i => Convert.ToBase64String(_textEncoder.GetBytes(i)), input)
: Try(i => _textEncoder.GetString(Convert.FromBase64String(i)), input);
private static string Try(Func<string, string> f, string input)
{
try
{
return f(input);
}
catch (FormatException e)
{
return e.Message;
}
}
}
class Rot13CipherService : ICipherService
{
public string Apply(string input, bool encrypt = false) =>
EncryptDecrypt(input);
private static string EncryptDecrypt(string input) =>
Rot13ForEach(input.ToCharArray());
private static string Rot13ForEach(IEnumerable<char> input) =>
new(input.Select(Rot13).ToArray());
private static char Rot13(char c) =>
c switch
{
>= 'a' and <= 'm' or >= 'A' and <= 'M' => (char)(c + 13),
>= 'n' and <= 'z' or >= 'N' and <= 'Z' => (char)(c - 13),
_ => c
};
}
static class App
{
private const string _defaultFeedback =
"Args: -(b|r|x){base64/rot13/xor cipher} [-k \"key\"] -(e|d){encrypt/decrypt} \"text to encrypt/decrypt\"";
public static void Run(string[] args, Action<string> cout, Encoding? textEncoder = null)
{
var arguments = ExtractArgs(args);
if (!IsValidArgs(arguments))
{
cout(_defaultFeedback);
return;
}
switch (arguments["cipher"])
{
case "b":
cout(ApplyBase64Cipher(arguments["input"], textEncoder, arguments["encrypt"] == "e"));
break;
case "r":
cout(ApplyRot13Cipher(arguments["input"]));
break;
case "x":
cout(ApplyXOrCipher(arguments["input"], textEncoder, arguments["key"]));
break;
}
}
private static bool IsValidArgs(IReadOnlyDictionary<string, string> arguments) =>
arguments.Count == 4
&& arguments.ContainsKey("key")
&& arguments.ContainsKey("cipher")
&& arguments.ContainsKey("encrypt")
&& arguments.ContainsKey("input");
private static IReadOnlyDictionary<string, string> ExtractArgs(
IReadOnlyList<string> args)
{
var value = new Dictionary<string, string> { { "key", "" } };
if (args.Count <= 2 || !args[0].StartsWith("-")) return value;
value.Add("cipher", args[0][^1].ToString());
if (args[1].StartsWith("-k") && args.Count > 3)
{
value["key"] = args[2];
if (!args[3].StartsWith("-")) return value;
value.Add("encrypt", args[3][1..]);
value.Add("input", args[4]);
}
else if (args[1].StartsWith("-"))
{
value.Add("encrypt", args[1][1..]);
value.Add("input", args[2]);
}
return value;
}
private static string ApplyXOrCipher(
string input, Encoding? textEncoder = null, string key = "") =>
GetXOrCipherService(key, textEncoder).Apply(input);
private static string ApplyRot13Cipher(string input) =>
GetRot13CipherService().Apply(input);
private static string ApplyBase64Cipher(
string input, Encoding? textEncoder = null, bool encrypt = false) =>
GetBase64CipherService(textEncoder).Apply(input, encrypt);
private static XOrCipherService GetXOrCipherService(
string key = "",
Encoding? textEncoder = null) => new XOrCipherService(key, textEncoder);
private static Base64CipherService GetBase64CipherService(
Encoding? textEncoder = null) => new Base64CipherService(textEncoder);
private static Rot13CipherService GetRot13CipherService() =>
new Rot13CipherService();
}
@savaged
Copy link
Author

savaged commented Mar 6, 2023

@savaged
Copy link
Author

savaged commented Jul 17, 2023

dotnet run -- -r -d "Uryyb Jbeyq"
dotnet run -- -b -d "SGVsbG8gV29ybGQ="

TODO: Revisit XOr cipher

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment