diff --git a/Algorithms.Tests/Encoders/AutokeyEncoderTests.cs b/Algorithms.Tests/Encoders/AutokeyEncoderTests.cs new file mode 100644 index 00000000..0613e1c6 --- /dev/null +++ b/Algorithms.Tests/Encoders/AutokeyEncoderTests.cs @@ -0,0 +1,26 @@ +using System; +using Algorithms.Encoders; +using NUnit.Framework; +using NUnit.Framework.Internal; + +namespace Algorithms.Tests.Encoders +{ + public static class AutokeyEncoderTests + { + [Test] + public static void DecodedStringIsTheSame() + { + // Arrange + var plainText = "PLAINTEXT"; + var keyword = "KEYWORD"; + var encoder = new AutokeyEncorder(); + + // Act + var encoded = encoder.Encode(plainText, keyword); + var decoded = encoder.Decode(encoded, keyword); + + // Assert + Assert.That(decoded, Is.EqualTo(plainText)); + } + } +} diff --git a/Algorithms/Encoders/AutokeyEncorder.cs b/Algorithms/Encoders/AutokeyEncorder.cs new file mode 100644 index 00000000..8dc13d37 --- /dev/null +++ b/Algorithms/Encoders/AutokeyEncorder.cs @@ -0,0 +1,69 @@ +using System; +using System.Globalization; +using System.Text; +using System.Text.RegularExpressions; + +namespace Algorithms.Encoders +{ + /// + /// Class for AutoKey encoding strings. + /// + public class AutokeyEncorder + { + /// + /// Autokey Cipher is a type of polyalphabetic cipher. + /// This works by choosing a key (a word or short phrase), + /// then you append the plaintext to itself to form a longer key. + /// + /// The string to be appended to the key. + /// The string to be appended to the plaintext. + /// The Autokey encoded string (All Uppercase). + public string Encode(string plainText, string keyword) + { + plainText = Regex.Replace(plainText.ToUpper(CultureInfo.InvariantCulture), "[^A-Z]", string.Empty); + keyword = keyword.ToUpper(CultureInfo.InvariantCulture); + + keyword += plainText; + + StringBuilder cipherText = new StringBuilder(); + + for(int i = 0; i < plainText.Length; i++) + { + char plainCharacter = plainText[i]; + char keyCharacter = keyword[i]; + + int encryptedCharacter = (plainCharacter - 'A' + keyCharacter - 'A') % 26 + 'A'; + cipherText.Append((char)encryptedCharacter); + } + + return cipherText.ToString(); + } + + /// + /// Removed the key from the encoded string. + /// + /// The encoded string. + /// The key to be removed from the encoded string. + /// The plaintext (All Uppercase). + public string Decode(string cipherText, string keyword) + { + cipherText = Regex.Replace(cipherText.ToUpper(CultureInfo.InvariantCulture), "[^A-Z]", string.Empty); + keyword = keyword.ToUpper(CultureInfo.InvariantCulture); + + StringBuilder plainText = new StringBuilder(); + StringBuilder extendedKeyword = new StringBuilder(keyword); + + for(int i = 0; i < cipherText.Length; i++) + { + char cipherCharacter = cipherText[i]; + char keywordCharacter = extendedKeyword[i]; + + int decryptedCharacter = (cipherCharacter - 'A' - (keywordCharacter - 'A') + 26) % 26 + 'A'; + plainText.Append((char)decryptedCharacter); + extendedKeyword.Append((char)decryptedCharacter); + } + + return plainText.ToString(); + } + } +} diff --git a/README.md b/README.md index 198d2bd7..b9933f9f 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ find more than one implementation for the same objective but using different alg * [Soundex](./Algorithms/Encoders/SoundexEncoder.cs) * [Feistel](./Algorithms/Encoders/FeistelCipher.cs) * [Blowfish](./Algorithms/Encoders/BlowfishEncoder.cs) + * [Autokey](./Algorithms/Encoders/AutokeyEncoder.cs) * [Graph](./Algorithms/Graph) * [Minimum Spanning Tree](./Algorithms/Graph/MinimumSpanningTree) * [Prim's Algorithm (Adjacency Matrix)](./Algorithms/Graph/MinimumSpanningTree/PrimMatrix.cs)