Semplice “offuscamento” bidirezionale e poco sicuro per C #

Sto cercando una semplice offuscazione (come criptare e decifrare ma non necessariamente sicura) per alcuni dati. Non è mission-critical. Ho bisogno di qualcosa per mantenere onesta la gente onesta, ma qualcosa di un po ‘più forte di ROT13 o Base64 .

Preferirei qualcosa che è già incluso nel .NET Framework 2.0, quindi non devo preoccuparmi di eventuali dipendenze esterne.

Non voglio davvero scherzare con le chiavi pubbliche / private, ecc. Non so molto sulla crittografia, ma so abbastanza per sapere che tutto ciò che ho scritto sarebbe meno che inutile … In realtà, Probabilmente avrei rovinato la matematica e reso banale il crack.

Altre risposte qui funzionano bene, ma AES è un algoritmo di crittografia più sicuro e aggiornato. Questa è una class che ho ottenuto alcuni anni fa per eseguire la crittografia AES che ho modificato nel tempo per essere più amichevole per le applicazioni Web (ad esempio, ho costruito i metodi Encrypt / Decrypt che funzionano con una stringa URL-friendly). Ha anche i metodi che funzionano con gli array di byte.

NOTA: è necessario utilizzare valori diversi negli array Key (32 byte) e Vector (16 byte)! Non vorresti che qualcuno calcolasse le tue chiavi assumendo che tu abbia usato questo codice così com’è! Tutto quello che devi fare è cambiare alcuni numeri (deve essere <= 255) negli array Key e Vector (ho lasciato un valore non valido nell'array Vector per assicurarti di farlo ...). Puoi usare https://www.random.org/bytes/ per generare facilmente un nuovo set:

  • generare Key
  • generare Vector

Usarlo è semplice: basta istanziare la class e quindi chiamare (di solito) EncryptToString (string StringToEncrypt) e DecryptString (string StringToDecrypt) come metodi. Non potrebbe essere più semplice (o più sicuro) una volta che avrai questa class sul posto.


 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; } } 

Ho pulito SimpleAES (sopra) per il mio uso. Corretti i metodi convinti di crittografia / decrittografia; metodi separati per codificare buffer di byte, stringhe e stringhe compatibili con l’URL; fatto uso di librerie esistenti per la codifica URL.

Il codice è piccolo, più semplice, più veloce e l’output è più conciso. Ad esempio, [email protected] produce:

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

Codice:

 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(); } } 

Sì, aggiungere l’assembly System.Security , importare lo spazio dei nomi System.Security.Cryptography . Ecco un semplice esempio di crittografia ad algoritmo simmetrico (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); 

Ho solo pensato di aggiungere che ho migliorato Simpler AES di Mud aggiungendo un IV casuale che è passato indietro nella stringa crittografata. Ciò migliora la crittografia poiché la crittografia della stessa stringa genererà un output diverso ogni volta.

 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 il test dell'unità bonus

 [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"); } 

Una variante di Marks (eccellente) risposta

  • Aggiungi “usando” s
  • Rendi la class IDisposable
  • Rimuovi il codice di codifica dell’URL per rendere l’esempio più semplice.
  • Aggiungi un semplice dispositivo di prova per dimostrare l’utilizzo

Spero che questo ti aiuti

 [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] Anni dopo, sono tornato per dire: non farlo! Scopri cosa c’è di sbagliato nella crittografia XOR? per dettagli.

Una crittografia bidirezionale molto semplice e facile è la crittografia XOR.

  1. Vieni con una password. Facciamolo essere mypass .
  2. Converti la password in binario (secondo ASCII). La password diventa 01101101 01111001 01110000 01100001 01110011 01110011.
  3. Prendi il messaggio che vuoi codificare. Converti anche questo in binario.
  4. Guarda la lunghezza del messaggio. Se la lunghezza del messaggio è di 400 byte, trasformare la password in una stringa da 400 byte ripetendola più e più volte. Diventerebbe 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 … (o mypassmypassmypass... )
  5. XOR il messaggio con la lunga password.
  6. Invia il risultato.
  7. Un’altra volta, XOR il messaggio crittografato con la stessa password ( mypassmypassmypass... ).
  8. C’è il tuo messaggio!

Se si desidera semplicemente una crittografia semplice (ovvero, ansible che un cracker deciso si interrompa, ma escluda la maggior parte degli utenti casuali), basta scegliere due passphrase di uguale lunghezza, ad esempio:

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

e i tuoi dati con entrambi (looping le passphrase se necessario) (a) . Per esempio:

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

Qualcuno che cerca il tuo binario potrebbe pensare che la stringa del DNA sia una chiave, ma è improbabile che pensi che il codice C sia qualcosa di diverso dalla memoria non inizializzata salvata con il tuo binario.


(a) Tenere presente che si tratta di una crittografia molto semplice e, secondo alcune definizioni, non può essere considerata affatto una crittografia (poiché l’intento della crittografia è di impedire l’accesso non autorizzato piuttosto che renderlo più difficile). Anche se, ovviamente, anche la crittografia più forte è insicura quando qualcuno sta sopra i portachiavi con un tubo d’acciaio.

Come affermato nella prima frase, questo è un mezzo per rendere abbastanza difficile per l’aggressore casuale che andrà avanti. È come prevenire i furti a casa tua – non è necessario renderlo inespugnabile, devi solo renderlo meno fertile della casa accanto 🙂

Ho combinato ciò che ho trovato il meglio da diverse risposte e commenti.

  • Vettore di inizializzazione casuale anteposto al testo crittografico (@jbtule)
  • Usa TransformFinalBlock () invece di MemoryStream (@RenniePet)
  • Nessun tasto precompilato per evitare che qualcuno copi e incolli un disastro
  • Smaltire e utilizzare correttamente i modelli

Codice:

 ///  /// 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(); } } 

Aggiornamento 2015-07-18: corretto errore nel metodo Encrypt () privato dai commenti di @bpsilver e @Evereq. IV è stato accidentalmente crittografato, è ora inserito in testo in chiaro come previsto da Decrypt ().

La crittografia è semplice: come altri hanno sottolineato, ci sono classi nello spazio dei nomi System.Security.Cryptography che fanno tutto il lavoro per te. Usali piuttosto che qualsiasi soluzione sviluppata in casa.

Ma la decifrazione è anche facile. Il problema che si presenta non è l’algoritmo di crittografia, ma protegge l’accesso alla chiave utilizzata per la decrittografia.

Vorrei utilizzare una delle seguenti soluzioni:

  • DPAPI che utilizza la class ProtectedData con ambito CurrentUser. Questo è facile in quanto non è necessario preoccuparsi di una chiave. I dati possono essere decifrati solo dallo stesso utente, quindi non sono utili per la condivisione di dati tra utenti o macchine.

  • DPAPI che utilizza la class ProtectedData con ambito LocalMachine. Ad esempio, per proteggere i dati di configurazione su un singolo server sicuro. Ma chiunque possa accedere alla macchina può crittografarlo, quindi non va bene a meno che il server non sia sicuro.

  • Qualsiasi algoritmo simmetrico. Generalmente utilizzo il metodo statico SymmetricAlgorithm.Create () se non mi interessa quale algoritmo viene utilizzato (in effetti è Rijndael per impostazione predefinita). In questo caso devi proteggere la tua chiave in qualche modo. Ad esempio puoi nasconderla in qualche modo e nasconderlo nel tuo codice. Ma sappi che chiunque sia abbastanza intelligente da decompilare il tuo codice sarà probabilmente in grado di trovare la chiave.

Volevo pubblicare la mia soluzione poiché nessuna delle soluzioni sopra descritte è semplice come la mia. Fatemi sapere cosa ne pensate:

  // 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))); } 

Opzionale

Ciò presuppone che MachineKey del server utilizzato per crittografare il valore sia uguale a quello utilizzato per decodificare il valore. Se lo si desidera, è ansible specificare un MachineKey statico in Web.config in modo che l’applicazione possa decodificare / crittografare i dati indipendentemente da dove viene eseguito (ad esempio, server di sviluppo o di produzione). È ansible generare una chiave di macchina statica seguendo queste istruzioni .

Lo spazio dei nomi System.Security.Cryptography contiene le classi TripleDESCryptoServiceProvider e RijndaelManaged

Non dimenticare di aggiungere un riferimento all’assembly System.Security .

Ho cambiato questo :

 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; } 

a questa:

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

Utilizzo di TripleDESCryptoServiceProvider in 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); } } 

So che hai detto che non ti importa di quanto sia sicuro, ma se hai scelto DES potresti anche prendere AES è il metodo di crittografia più aggiornato.

Utilizzando la libreria incorporata .Net Cryptography, questo esempio mostra come utilizzare 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; } } } 

I’ve been using the accepted answer by Mark Brittingham and its has helped me a lot. Recently I had to send encrypted text to a different organization and that’s where some issues came up. The OP does not require these options but since this is a popular question I’m posting my modification ( Encrypt and Decrypt functions borrowed from here ):

  1. Different IV for every message – Concatenates IV bytes to the cipher bytes before obtaining the hex. Of course this is a convention that needs to be conveyed to the parties receiving the cipher text.
  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 formsd 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; } } 

inserisci la descrizione dell'immagine qui

I think this is the worlds simplest one !

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

Test

  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