Simples “obfuscation” bidirecional inseguro para C #

Eu estou procurando por uma ofuscação muito simples (como criptografar e descriptografar, mas não necessariamente segura) a funcionalidade para alguns dados. Não é missão crítica. Eu preciso de algo para manter as pessoas honestas honestas, mas algo um pouco mais forte que o ROT13 ou o Base64 .

Eu prefiro algo que já está incluído no .NET Framework 2.0, então não preciso me preocupar com nenhuma dependência externa.

Eu realmente não quero ter que mexer com chaves públicas / privadas, etc. Eu não sei muito sobre criptografia, mas eu sei o suficiente para saber que qualquer coisa que eu escrevi seria menos que inútil … Na verdade, Eu provavelmente estragaria a matemática e tornaria trivial para quebrar.

    Outras respostas aqui funcionam bem, mas o AES é um algoritmo de criptografia mais seguro e atualizado. Esta é uma class que eu obtive há alguns anos para executar a criptografia AES que modifiquei ao longo do tempo para ser mais amigável para aplicativos da web (por exemplo, criei methods Encrypt / Decrypt que funcionam com string compatível com URL). Ele também tem os methods que funcionam com matrizes de bytes.

    NOTA: você deve usar valores diferentes nos arrays Key (32 bytes) e Vector (16 bytes)! Você não gostaria que alguém descobrisse suas chaves simplesmente assumindo que você usou este código como está! Tudo o que você precisa fazer é alterar alguns dos números (deve ser < = 255) nos arrays Key e Vector (deixei um valor inválido no array Vector para garantir que você faça isso ...). Você pode usar https://www.random.org/bytes/ para gerar um novo conjunto facilmente:

    • gerar Key
    • gerar Vector

    Usá-lo é fácil: basta instanciar a class e, em seguida, chamar (normalmente) EncryptToString (string StringToEncrypt) e DecryptString (string StringToDecrypt) como methods. Não poderia ser mais fácil (ou mais seguro) depois de ter essa aula no lugar.


     using System; using System.Data; using System.Security.Cryptography; using System.IO; public class SimpleAES { // Change these keys private byte[] Key = __Replace_Me__({ 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 }); // a hardcoded IV should not be used for production AES-CBC code // IVs should be unpredictable per ciphertext private byte[] Vector = __Replace_Me__({ 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 2521, 112, 79, 32, 114, 156 }); private ICryptoTransform EncryptorTransform, DecryptorTransform; private System.Text.UTF8Encoding UTFEncoder; public SimpleAES() { //This is our encryption method RijndaelManaged rm = new RijndaelManaged(); //Create an encryptor and a decryptor using our encryption method, key, and vector. EncryptorTransform = rm.CreateEncryptor(this.Key, this.Vector); DecryptorTransform = rm.CreateDecryptor(this.Key, this.Vector); //Used to translate bytes to text and vice versa UTFEncoder = new System.Text.UTF8Encoding(); } /// -------------- Two Utility Methods (not used but may be useful) ----------- /// Generates an encryption key. static public byte[] GenerateEncryptionKey() { //Generate a Key. RijndaelManaged rm = new RijndaelManaged(); rm.GenerateKey(); return rm.Key; } /// Generates a unique encryption vector static public byte[] GenerateEncryptionVector() { //Generate a Vector RijndaelManaged rm = new RijndaelManaged(); rm.GenerateIV(); return rm.IV; } /// ----------- The commonly used methods ------------------------------ /// Encrypt some text and return a string suitable for passing in a URL. public string EncryptToString(string TextValue) { return ByteArrToString(Encrypt(TextValue)); } /// Encrypt some text and return an encrypted byte array. public byte[] Encrypt(string TextValue) { //Translates our text value into a byte array. Byte[] bytes = UTFEncoder.GetBytes(TextValue); //Used to stream the data in and out of the CryptoStream. MemoryStream memoryStream = new MemoryStream(); /* * We will have to write the unencrypted bytes to the stream, * then read the encrypted result back from the stream. */ #region Write the decrypted value to the encryption stream CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write); cs.Write(bytes, 0, bytes.Length); cs.FlushFinalBlock(); #endregion #region Read encrypted value back out of the stream memoryStream.Position = 0; byte[] encrypted = new byte[memoryStream.Length]; memoryStream.Read(encrypted, 0, encrypted.Length); #endregion //Clean up. cs.Close(); memoryStream.Close(); return encrypted; } /// The other side: Decryption methods public string DecryptString(string EncryptedString) { return Decrypt(StrToByteArray(EncryptedString)); } /// Decryption when working with byte arrays. public string Decrypt(byte[] EncryptedValue) { #region Write the encrypted value to the decryption stream MemoryStream encryptedStream = new MemoryStream(); CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write); decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length); decryptStream.FlushFinalBlock(); #endregion #region Read the decrypted value from the stream. encryptedStream.Position = 0; Byte[] decryptedBytes = new Byte[encryptedStream.Length]; encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length); encryptedStream.Close(); #endregion return UTFEncoder.GetString(decryptedBytes); } /// Convert a string to a byte array. NOTE: Normally we'd create a Byte Array from a string using an ASCII encoding (like so). // System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); // return encoding.GetBytes(str); // However, this results in character values that cannot be passed in a URL. So, instead, I just // lay out all of the byte values in a long string of numbers (three per - must pad numbers less than 100). public byte[] StrToByteArray(string str) { if (str.Length == 0) throw new Exception("Invalid string value in StrToByteArray"); byte val; byte[] byteArr = new byte[str.Length / 3]; int i = 0; int j = 0; do { val = byte.Parse(str.Substring(i, 3)); byteArr[j++] = val; i += 3; } while (i < str.Length); return byteArr; } // Same comment as above. Normally the conversion would use an ASCII encoding in the other direction: // System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); // return enc.GetString(byteArr); public string ByteArrToString(byte[] byteArr) { byte val; string tempStr = ""; for (int i = 0; i <= byteArr.GetUpperBound(0); i++) { val = byteArr[i]; if (val < (byte)10) tempStr += "00" + val.ToString(); else if (val < (byte)100) tempStr += "0" + val.ToString(); else tempStr += val.ToString(); } return tempStr; } } 

    Eu limpei SimpleAES (acima) para o meu uso. Corrigidos methods criptografados / decriptografados; methods separados para codificar buffers de byte, strings e strings amigáveis ​​para URL; fez uso de bibliotecas existentes para codificação de URL.

    O código é pequeno, mais simples, mais rápido e a saída é mais concisa. Por exemplo, johnsmith@gmail.com produz:

     SimpleAES: "096114178117140150104121138042115022037019164188092040214235183167012211175176167001017163166152" SimplerAES: "YHKydYyWaHmKKnMWJROkvFwo1uu3pwzTr7CnARGjppg%3d" 

    Código:

     public class SimplerAES { private static byte[] key = __Replace_Me__({ 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 }); // a hardcoded IV should not be used for production AES-CBC code // IVs should be unpredictable per ciphertext private static byte[] vector = __Replace_Me_({ 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 221, 112, 79, 32, 114, 156 }); private ICryptoTransform encryptor, decryptor; private UTF8Encoding encoder; public SimplerAES() { RijndaelManaged rm = new RijndaelManaged(); encryptor = rm.CreateEncryptor(key, vector); decryptor = rm.CreateDecryptor(key, vector); encoder = new UTF8Encoding(); } public string Encrypt(string unencrypted) { return Convert.ToBase64String(Encrypt(encoder.GetBytes(unencrypted))); } public string Decrypt(string encrypted) { return encoder.GetString(Decrypt(Convert.FromBase64String(encrypted))); } public byte[] Encrypt(byte[] buffer) { return Transform(buffer, encryptor); } public byte[] Decrypt(byte[] buffer) { return Transform(buffer, decryptor); } protected byte[] Transform(byte[] buffer, ICryptoTransform transform) { MemoryStream stream = new MemoryStream(); using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write)) { cs.Write(buffer, 0, buffer.Length); } return stream.ToArray(); } } 

    Sim, adicione o assembly System.Security , importe o namespace System.Security.Cryptography . Aqui está um exemplo simples de criptografia de algoritmo simétrico (DES):

     DESCryptoServiceProvider des = new DESCryptoServiceProvider(); des.GenerateKey(); byte[] key = des.Key; // save this! ICryptoTransform encryptor = des.CreateEncryptor(); // encrypt byte[] enc = encryptor.TransformFinalBlock(new byte[] { 1, 2, 3, 4 }, 0, 4); ICryptoTransform decryptor = des.CreateDecryptor(); // decrypt byte[] originalAgain = decryptor.TransformFinalBlock(enc, 0, enc.Length); Debug.Assert(originalAgain[0] == 1); 

    Apenas pensei em acrescentar que melhorei o SimplerAES de Mud adicionando um IV random que é passado de volta dentro da string criptografada. Isso melhora a criptografia, pois a criptografia da mesma sequência resultará em uma saída diferente a cada vez.

     public class StringEncryption { private readonly Random random; private readonly byte[] key; private readonly RijndaelManaged rm; private readonly UTF8Encoding encoder; public StringEncryption() { this.random = new Random(); this.rm = new RijndaelManaged(); this.encoder = new UTF8Encoding(); this.key = Convert.FromBase64String("Your+Secret+Static+Encryption+Key+Goes+Here="); } public string Encrypt(string unencrypted) { var vector = new byte[16]; this.random.NextBytes(vector); var cryptogram = vector.Concat(this.Encrypt(this.encoder.GetBytes(unencrypted), vector)); return Convert.ToBase64String(cryptogram.ToArray()); } public string Decrypt(string encrypted) { var cryptogram = Convert.FromBase64String(encrypted); if (cryptogram.Length < 17) { throw new ArgumentException("Not a valid encrypted string", "encrypted"); } var vector = cryptogram.Take(16).ToArray(); var buffer = cryptogram.Skip(16).ToArray(); return this.encoder.GetString(this.Decrypt(buffer, vector)); } private byte[] Encrypt(byte[] buffer, byte[] vector) { var encryptor = this.rm.CreateEncryptor(this.key, vector); return this.Transform(buffer, encryptor); } private byte[] Decrypt(byte[] buffer, byte[] vector) { var decryptor = this.rm.CreateDecryptor(this.key, vector); return this.Transform(buffer, decryptor); } private byte[] Transform(byte[] buffer, ICryptoTransform transform) { var stream = new MemoryStream(); using (var cs = new CryptoStream(stream, transform, CryptoStreamMode.Write)) { cs.Write(buffer, 0, buffer.Length); } return stream.ToArray(); } } 

    E teste de unidade de bônus

     [Test] public void EncryptDecrypt() { // Arrange var subject = new StringEncryption(); var originalString = "Testing123!£$"; // Act var encryptedString1 = subject.Encrypt(originalString); var encryptedString2 = subject.Encrypt(originalString); var decryptedString1 = subject.Decrypt(encryptedString1); var decryptedString2 = subject.Decrypt(encryptedString2); // Assert Assert.AreEqual(originalString, decryptedString1, "Decrypted string should match original string"); Assert.AreEqual(originalString, decryptedString2, "Decrypted string should match original string"); Assert.AreNotEqual(originalString, encryptedString1, "Encrypted string should not match original string"); Assert.AreNotEqual(encryptedString1, encryptedString2, "String should never be encrypted the same twice"); } 

    Uma variante da resposta Marcas (excelente)

    • Adicionar “usando” s
    • Tornar a class IDisponível
    • Remova o código de codificação de URL para simplificar o exemplo.
    • Adicione um dispositivo de teste simples para demonstrar o uso

    Espero que isto ajude

     [TestFixture] public class RijndaelHelperTests { [Test] public void UseCase() { //These two values should not be hard coded in your code. byte[] key = {251, 9, 67, 117, 237, 158, 138, 150, 255, 97, 103, 128, 183, 65, 76, 161, 7, 79, 244, 225, 146, 180, 51, 123, 118, 167, 45, 10, 184, 181, 202, 190}; byte[] vector = {214, 11, 221, 108, 210, 71, 14, 15, 151, 57, 241, 174, 177, 142, 115, 137}; using (var rijndaelHelper = new RijndaelHelper(key, vector)) { var encrypt = rijndaelHelper.Encrypt("StringToEncrypt"); var decrypt = rijndaelHelper.Decrypt(encrypt); Assert.AreEqual("StringToEncrypt", decrypt); } } } public class RijndaelHelper : IDisposable { Rijndael rijndael; UTF8Encoding encoding; public RijndaelHelper(byte[] key, byte[] vector) { encoding = new UTF8Encoding(); rijndael = Rijndael.Create(); rijndael.Key = key; rijndael.IV = vector; } public byte[] Encrypt(string valueToEncrypt) { var bytes = encoding.GetBytes(valueToEncrypt); using (var encryptor = rijndael.CreateEncryptor()) using (var stream = new MemoryStream()) using (var crypto = new CryptoStream(stream, encryptor, CryptoStreamMode.Write)) { crypto.Write(bytes, 0, bytes.Length); crypto.FlushFinalBlock(); stream.Position = 0; var encrypted = new byte[stream.Length]; stream.Read(encrypted, 0, encrypted.Length); return encrypted; } } public string Decrypt(byte[] encryptedValue) { using (var decryptor = rijndael.CreateDecryptor()) using (var stream = new MemoryStream()) using (var crypto = new CryptoStream(stream, decryptor, CryptoStreamMode.Write)) { crypto.Write(encryptedValue, 0, encryptedValue.Length); crypto.FlushFinalBlock(); stream.Position = 0; var decryptedBytes = new Byte[stream.Length]; stream.Read(decryptedBytes, 0, decryptedBytes.Length); return encoding.GetString(decryptedBytes); } } public void Dispose() { if (rijndael != null) { rijndael.Dispose(); } } } 

    [EDIT] Anos depois, voltei a dizer: não faça isso! Veja o que há de errado com a criptografia XOR? para detalhes.

    Um criptografia de duas vias muito simples e fácil é a criptografia XOR.

    1. Invente uma senha. Vamos ter que ser mypass .
    2. Converta a senha em binário (de acordo com ASCII). A senha se torna 01101101 01111001 01110000 01100001 01110011 01110011.
    3. Pegue a mensagem que você deseja codificar. Converta isso em binário também.
    4. Olhe o comprimento da mensagem. Se o comprimento da mensagem for de 400 bytes, transforme a senha em uma cadeia de 400 bytes, repetindo-a repetidamente. Seria 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 … (ou mypassmypassmypass... )
    5. XOR a mensagem com a senha longa.
    6. Envie o resultado.
    7. Outra vez, XOR a mensagem criptografada com a mesma senha ( mypassmypassmypass... ).
    8. Esta é a sua mensagem!

    Se você quer apenas criptografia simples (ou seja, possível para um cracker determinado quebrar, mas bloqueando a maioria dos usuários casuais), basta escolher duas senhas de tamanho igual, por exemplo:

     deoxyribonucleicacid while (x>0) { x-- }; 

    e xor seus dados com ambos (looping as senhas se necessário) (a) . Por exemplo:

     1111-2222-3333-4444-5555-6666-7777 deoxyribonucleicaciddeoxyribonucle while (x>0) { x-- };while (x>0) { 

    Alguém que esteja procurando em seu binário pode pensar que a cadeia de DNA é uma chave, mas é improvável que pense que o código C seja outra coisa senão a memory não inicializada salva com o seu binário.


    (a) Tenha em mente que esta é uma criptografia muito simples e, por algumas definições, pode não ser considerada criptografia (já que a intenção da criptografia é impedir o access não autorizado, em vez de apenas torná-lo mais difícil). Embora, é claro, mesmo a criptografia mais forte seja insegura quando alguém está sobre os porta-chaves com um tubo de aço.

    Como dito na primeira frase, isso é um meio de dificultar o ataque do atacante casual. É semelhante a evitar assaltos em sua casa – você não precisa torná-lo inexpugnável, você só precisa torná-lo menos depreciável do que a casa ao lado 🙂

    Combinei o que achei melhor com várias respostas e comentários.

    • Vetor de boot aleatória anexado ao texto criptografado (@jbtule)
    • Use TransformFinalBlock () em vez de MemoryStream (@RenniePet)
    • Sem chaves pré-preenchidas para evitar que alguém copie e cole um desastre
    • Descarte e uso adequados de padrões

    Código:

     ///  /// Simple encryption/decryption using a random initialization vector /// and prepending it to the crypto text. ///  /// Based on multiple answers in http://stackoverflow.com/questions/165808/simple-two-way-encryption-for-c-sharp  public class SimpleAes : IDisposable { ///  /// Initialization vector length in bytes. ///  private const int IvBytes = 16; ///  /// Must be exactly 16, 24 or 32 bytes long. ///  private static readonly byte[] Key = Convert.FromBase64String("FILL ME WITH 24 (2 pad chars), 32 OR 44 (1 pad char) RANDOM CHARS"); // Base64 has a blowup of four-thirds (33%) private readonly UTF8Encoding _encoder; private readonly ICryptoTransform _encryptor; private readonly RijndaelManaged _rijndael; public SimpleAes() { _rijndael = new RijndaelManaged {Key = Key}; _rijndael.GenerateIV(); _encryptor = _rijndael.CreateEncryptor(); _encoder = new UTF8Encoding(); } public string Decrypt(string encrypted) { return _encoder.GetString(Decrypt(Convert.FromBase64String(encrypted))); } public void Dispose() { _rijndael.Dispose(); _encryptor.Dispose(); } public string Encrypt(string unencrypted) { return Convert.ToBase64String(Encrypt(_encoder.GetBytes(unencrypted))); } private byte[] Decrypt(byte[] buffer) { // IV is prepended to cryptotext byte[] iv = buffer.Take(IvBytes).ToArray(); using (ICryptoTransform decryptor = _rijndael.CreateDecryptor(_rijndael.Key, iv)) { return decryptor.TransformFinalBlock(buffer, IvBytes, buffer.Length - IvBytes); } } private byte[] Encrypt(byte[] buffer) { // Prepend cryptotext with IV byte [] inputBuffer = _encryptor.TransformFinalBlock(buffer, 0, buffer.Length); return _rijndael.IV.Concat(inputBuffer).ToArray(); } } 

    Atualização 2015-07-18: Corrigido erro no método privado Encrypt () pelos comentários de @bpsilver e @Evereq. IV foi acidentalmente criptografado, agora é precedido em texto não criptografado como esperado por Decrypt ().

    A criptografia é fácil: como outros apontaram, há classs no namespace System.Security.Cryptography que fazem todo o trabalho para você. Use-os em vez de qualquer solução doméstica.

    Mas a descriptografia é fácil também. O problema que você tem não é o algoritmo de criptografia, mas protege o access à chave usada para descriptografia.

    Eu usaria uma das seguintes soluções:

    • DPAPI usando a class ProtectedData com o escopo CurrentUser. Isso é fácil, pois você não precisa se preocupar com uma chave. Os dados só podem ser descriptografados pelo mesmo usuário, portanto não é bom compartilhar dados entre usuários ou máquinas.

    • DPAPI usando a class ProtectedData com o escopo LocalMachine. Bom para, por exemplo, proteger os dados de configuração em um único servidor seguro. Mas qualquer pessoa que possa fazer login na máquina pode criptografá-lo, portanto, não é bom, a menos que o servidor esteja seguro.

    • Algum algoritmo simétrico. Eu normalmente uso o método estático SymmetricAlgorithm.Create () se eu não me importo com qual algoritmo é usado (na verdade, é o Rijndael por padrão). Neste caso, você precisa proteger sua chave de alguma forma. Por exemplo, você pode ofuscar de alguma forma e escondê-lo em seu código. Mas esteja ciente de que qualquer um que seja inteligente o suficiente para descompilar seu código provavelmente conseguirá encontrar a chave.

    Eu queria postar minha solução já que nenhuma das soluções acima é tão simples quanto a minha. Diz-me o que pensas:

      // This will return an encrypted string based on the unencrypted parameter public static string Encrypt(this string DecryptedValue) { HttpServerUtility.UrlTokenEncode(MachineKey.Protect(Encoding.UTF8.GetBytes(DecryptedValue.Trim()))); } // This will return an unencrypted string based on the parameter public static string Decrypt(this string EncryptedValue) { Encoding.UTF8.GetString(MachineKey.Unprotect(HttpServerUtility.UrlTokenDecode(EncryptedValue))); } 

    Opcional

    Isso pressupõe que o MachineKey do servidor usado para criptografar o valor é o mesmo usado para descriptografar o valor. Se desejar, você pode especificar um MachineKey estático no Web.config para que seu aplicativo possa descriptografar / criptografar dados, independentemente de onde ele é executado (por exemplo, servidor de desenvolvimento vs. de produção). Você pode gerar uma chave de máquina estática seguindo estas instruções .

    O namespace System.Security.Cryptography contém as classs TripleDESCryptoServiceProvider e RijndaelManaged

    Não esqueça de adicionar uma referência ao assembly System.Security .

    Eu mudei isso :

     public string ByteArrToString(byte[] byteArr) { byte val; string tempStr = ""; for (int i = 0; i < = byteArr.GetUpperBound(0); i++) { val = byteArr[i]; if (val < (byte)10) tempStr += "00" + val.ToString(); else if (val < (byte)100) tempStr += "0" + val.ToString(); else tempStr += val.ToString(); } return tempStr; } 

    para isso:

      public string ByteArrToString(byte[] byteArr) { string temp = ""; foreach (byte b in byteArr) temp += b.ToString().PadLeft(3, '0'); return temp; } 

    Usando TripleDESCryptoServiceProvider em System.Security.Cryptography :

     public static class CryptoHelper { private const string Key = "MyHashString"; private static TripleDESCryptoServiceProvider GetCryproProvider() { var md5 = new MD5CryptoServiceProvider(); var key = md5.ComputeHash(Encoding.UTF8.GetBytes(Key)); return new TripleDESCryptoServiceProvider() { Key = key, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 }; } public static string Encrypt(string plainString) { var data = Encoding.UTF8.GetBytes(plainString); var tripleDes = GetCryproProvider(); var transform = tripleDes.CreateEncryptor(); var resultsByteArray = transform.TransformFinalBlock(data, 0, data.Length); return Convert.ToBase64String(resultsByteArray); } public static string Decrypt(string encryptedString) { var data = Convert.FromBase64String(encryptedString); var tripleDes = GetCryproProvider(); var transform = tripleDes.CreateDecryptor(); var resultsByteArray = transform.TransformFinalBlock(data, 0, data.Length); return Encoding.UTF8.GetString(resultsByteArray); } } 

    Eu sei que você disse que não se importa com o quão seguro é, mas se você escolheu o DES você pode muito bem tomar o AES , é o método de criptografia mais atualizado.

    Usando a biblioteca de criptografia .NET incorporada, este exemplo mostra como usar o Advanced Encryption Standard (AES).

     using System; using System.IO; using System.Security.Cryptography; namespace Aes_Example { class AesExample { public static void Main() { try { string original = "Here is some data to encrypt!"; // Create a new instance of the Aes // class. This generates a new key and initialization // vector (IV). using (Aes myAes = Aes.Create()) { // Encrypt the string to an array of bytes. byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV); // Decrypt the bytes to a string. string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV); //Display the original data and the decrypted data. Console.WriteLine("Original: {0}", original); Console.WriteLine("Round Trip: {0}", roundtrip); } } catch (Exception e) { Console.WriteLine("Error: {0}", e.Message); } } static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key,byte[] IV) { // Check arguments. if (plainText == null || plainText.Length < = 0) throw new ArgumentNullException("plainText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("Key"); byte[] encrypted; // Create an Aes object // with the specified key and IV. using (Aes aesAlg = Aes.Create()) { aesAlg.Key = Key; aesAlg.IV = IV; // Create a decrytor to perform the stream transform. ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { //Write all data to the stream. swEncrypt.Write(plainText); } encrypted = msEncrypt.ToArray(); } } } // Return the encrypted bytes from the memory stream. return encrypted; } static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV) { // Check arguments. if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("Key"); // Declare the string used to hold // the decrypted text. string plaintext = null; // Create an Aes object // with the specified key and IV. using (Aes aesAlg = Aes.Create()) { aesAlg.Key = Key; aesAlg.IV = IV; // Create a decrytor to perform the stream transform. ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); // Create the streams used for decryption. using (MemoryStream msDecrypt = new MemoryStream(cipherText)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { // Read the decrypted bytes from the decrypting stream // and place them in a string. plaintext = srDecrypt.ReadToEnd(); } } } } return plaintext; } } } 

    Eu tenho usado a resposta aceita por Mark Brittingham e isso me ajudou muito. Recentemente, tive que enviar texto criptografado para uma organização diferente e foi aí que surgiram alguns problemas. O OP não requer essas opções, mas como essa é uma pergunta popular, estou postando minha modificação ( Encrypt e Decrypt funções emprestadas daqui ):

    1. Diferente IV para cada mensagem – Concatena os bytes IV aos bytes cifrados antes de obter o hex. Claro que esta é uma convenção que precisa ser transmitida para as partes que recebem o texto cifrado.
    2. Allows two constructors – one for default RijndaelManaged values, and one where property values can be specified (based on mutual agreement between encrypting and decrypting parties)

    Here is the class (test sample at the end):

     ///  /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx /// Uses UTF8 Encoding /// http://security.stackexchange.com/a/90850 ///  public class AnotherAES : IDisposable { private RijndaelManaged rijn; ///  /// Initialize algo with key, block size, key size, padding mode and cipher mode to be known. ///  /// ASCII key to be used for encryption or decryption /// block size to use for AES algorithm. 128, 192 or 256 bits /// key length to use for AES algorithm. 128, 192, or 256 bits ///  ///  public AnotherAES(string key, int blockSize, int keySize, PaddingMode paddingMode, CipherMode cipherMode) { rijn = new RijndaelManaged(); rijn.Key = Encoding.UTF8.GetBytes(key); rijn.BlockSize = blockSize; rijn.KeySize = keySize; rijn.Padding = paddingMode; rijn.Mode = cipherMode; } ///  /// Initialize algo just with key /// Defaults for RijndaelManaged class: /// Block Size: 256 bits (32 bytes) /// Key Size: 128 bits (16 bytes) /// Padding Mode: PKCS7 /// Cipher Mode: CBC ///  ///  public AnotherAES(string key) { rijn = new RijndaelManaged(); byte[] keyArray = Encoding.UTF8.GetBytes(key); rijn.Key = keyArray; } ///  /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx /// Encrypt a string using RijndaelManaged encryptor. ///  /// string to be encrypted /// initialization vector to be used by crypto algorithm ///  public byte[] Encrypt(string plainText, byte[] IV) { if (rijn == null) throw new ArgumentNullException("Provider not initialized"); // Check arguments. if (plainText == null || plainText.Length < = 0) throw new ArgumentNullException("plainText cannot be null or empty"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV cannot be null or empty"); byte[] encrypted; // Create a decrytor to perform the stream transform. using (ICryptoTransform encryptor = rijn.CreateEncryptor(rijn.Key, IV)) { // Create the streams used for encryption. using (MemoryStream msEncrypt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt)) { //Write all data to the stream. swEncrypt.Write(plainText); } encrypted = msEncrypt.ToArray(); } } } // Return the encrypted bytes from the memory stream. return encrypted; }//end EncryptStringToBytes ///  /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx ///  /// bytes to be decrypted back to plaintext /// initialization vector used to encrypt the bytes ///  public string Decrypt(byte[] cipherText, byte[] IV) { if (rijn == null) throw new ArgumentNullException("Provider not initialized"); // Check arguments. if (cipherText == null || cipherText.Length < = 0) throw new ArgumentNullException("cipherText cannot be null or empty"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("IV cannot be null or empty"); // Declare the string used to hold the decrypted text. string plaintext = null; // Create a decrytor to perform the stream transform. using (ICryptoTransform decryptor = rijn.CreateDecryptor(rijn.Key, IV)) { // Create the streams used for decryption. using (MemoryStream msDecrypt = new MemoryStream(cipherText)) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { using (StreamReader srDecrypt = new StreamReader(csDecrypt)) { // Read the decrypted bytes from the decrypting stream and place them in a string. plaintext = srDecrypt.ReadToEnd(); } } } } return plaintext; }//end DecryptStringFromBytes ///  /// Generates a unique encryption vector using RijndaelManaged.GenerateIV() method ///  ///  public byte[] GenerateEncryptionVector() { if (rijn == null) throw new ArgumentNullException("Provider not initialized"); //Generate a Vector rijn.GenerateIV(); return rijn.IV; }//end GenerateEncryptionVector ///  /// Based on https://stackoverflow.com/a/1344255 /// Generate a unique string given number of bytes required. /// This string can be used as IV. IV byte size should be equal to cipher-block byte size. /// Allows seeing IV in plaintext so it can be passed along a url or some message. ///  ///  ///  public static string GetUniqueString(int numBytes) { char[] chars = new char[62]; chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); byte[] data = new byte[1]; using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider()) { data = new byte[numBytes]; crypto.GetBytes(data); } StringBuilder result = new StringBuilder(numBytes); foreach (byte b in data) { result.Append(chars[b % (chars.Length)]); } return result.ToString(); }//end GetUniqueKey() ///  /// Converts a string to byte array. Useful when converting back hex string which was originally formed from bytes. ///  ///  ///  public static byte[] StringToByteArray(String hex) { int NumberChars = hex.Length; byte[] bytes = new byte[NumberChars / 2]; for (int i = 0; i < NumberChars; i += 2) bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); return bytes; }//end StringToByteArray ///  /// Dispose RijndaelManaged object initialized in the constructor ///  public void Dispose() { if (rijn != null) rijn.Dispose(); }//end Dispose() }//end class 

    e..

    Here is the test sample:

     class Program { string key; static void Main(string[] args) { Program p = new Program(); //get 16 byte key (just demo - typically you will have a predetermined key) p.key = AnotherAES.GetUniqueString(16); string plainText = "Hello World!"; //encrypt string hex = p.Encrypt(plainText); //decrypt string roundTrip = p.Decrypt(hex); Console.WriteLine("Round Trip: {0}", roundTrip); } string Encrypt(string plainText) { Console.WriteLine("\nSending (encrypt side)..."); Console.WriteLine("Plain Text: {0}", plainText); Console.WriteLine("Key: {0}", key); string hex = string.Empty; string ivString = AnotherAES.GetUniqueString(16); Console.WriteLine("IV: {0}", ivString); using (AnotherAES aes = new AnotherAES(key)) { //encrypting side byte[] IV = Encoding.UTF8.GetBytes(ivString); //get encrypted bytes (IV bytes prepended to cipher bytes) byte[] encryptedBytes = aes.Encrypt(plainText, IV); byte[] encryptedBytesWithIV = IV.Concat(encryptedBytes).ToArray(); //get hex string to send with url //this hex has both IV and ciphertext hex = BitConverter.ToString(encryptedBytesWithIV).Replace("-", ""); Console.WriteLine("sending hex: {0}", hex); } return hex; } string Decrypt(string hex) { Console.WriteLine("\nReceiving (decrypt side)..."); Console.WriteLine("received hex: {0}", hex); string roundTrip = string.Empty; Console.WriteLine("Key " + key); using (AnotherAES aes = new AnotherAES(key)) { //get bytes from url byte[] encryptedBytesWithIV = AnotherAES.StringToByteArray(hex); byte[] IV = encryptedBytesWithIV.Take(16).ToArray(); Console.WriteLine("IV: {0}", System.Text.Encoding.Default.GetString(IV)); byte[] cipher = encryptedBytesWithIV.Skip(16).ToArray(); roundTrip = aes.Decrypt(cipher, IV); } return roundTrip; } } 

    insira a descrição da imagem aqui

    I think this is the worlds simplest one !

     string encrypted = "Text".Aggregate("", (c, a) => c + (char) (a + 2)); 

    Teste

      Console.WriteLine(("Hello").Aggregate("", (c, a) => c + (char) (a + 1))); //Output is Ifmmp Console.WriteLine(("Ifmmp").Aggregate("", (c, a) => c + (char)(a - 1))); //Output is Hello