Простая небезопасная двусторонняя “обфускация” для C#

StackOverflow https://stackoverflow.com/questions/165808

  •  03-07-2019
  •  | 
  •  

Вопрос

Я ищу очень простую функцию запутывания (например, шифрования и дешифрования, но не обязательно безопасного) для некоторых данных.Это не критичная миссия.Мне нужно что-то, что заставит честных людей быть честными, но что-то немного посильнее, чем РОТ13 или Base64.

Я бы предпочел что-то, что уже включено в .NET framework 2.0, так что мне не нужно беспокоиться о каких-либо внешних зависимостях.

Я действительно не хочу возиться с открытыми / закрытыми ключами и т.д.Я не так уж много знаю о шифровании, но я знаю достаточно, чтобы понимать, что все, что я написал, было бы менее чем бесполезным...На самом деле, я бы, вероятно, напортачил с математикой и сделал бы ее тривиальной для взлома.

Это было полезно?

Решение

Другие ответы здесь работают нормально, но AES - это более безопасный и современный алгоритм шифрования.Это класс, который я получил несколько лет назад для выполнения шифрования AES, который со временем я модифицировал, чтобы сделать его более удобным для веб-приложений (например,Я создал методы шифрования / дешифрования, которые работают с удобной для URL-адресов строкой).В нем также есть методы, которые работают с байтовыми массивами.

ПРИМЕЧАНИЕ:вы должны использовать разные значения в массивах ключей (32 байта) и векторов (16 байт)!Вы же не хотели бы, чтобы кто-то вычислил ваши ключи, просто предположив, что вы использовали этот код как есть!Все, что вам нужно сделать, это изменить некоторые цифры (должны быть <= 255) в массивах ключей и векторов (я оставил одно недопустимое значение в векторном массиве, чтобы убедиться, что вы это сделаете ...).Вы можете использовать https://www.random.org/bytes/ легко создавать новый набор:

Пользоваться им очень просто:просто создайте экземпляр класса, а затем вызовите (обычно) EncryptToString(строка StringToEncrypt) и DecryptString(строка StringToDecrypt) в качестве методов.Это не может быть проще (или безопаснее), если у вас есть этот класс.


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

Другие советы

Я очистил SimpleAES (выше) для своего использования.Исправлены запутанные методы шифрования / дешифрования;отдельные методы кодирования байтовых буферов, строк и строк, удобных для URL-адресов;использовал существующие библиотеки для кодирования URL-адресов.

Код небольшой, простой, быстрый, а выходные данные более краткие.Например, johnsmith@gmail.com производит:

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

Код:

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

Да, добавьте сборку System.Security , импортируйте пространство имен System.Security.Cryptography . Вот простой пример симметричного (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);

Просто подумал, что добавлю, что я улучшил SimplerAES Mud, добавив случайный IV, который передается обратно в зашифрованную строку. Это улучшает шифрование, поскольку шифрование одной и той же строки каждый раз приводит к разным выводам.

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

И бонусный юнит-тест

[Test]
public void EncryptDecrypt()
{
    // Arrange
    var subject = new StringEncryption();
    var originalString = "Testing123!£<*>quot;;

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

Вариант ответа с отметками "отлично"

  • Добавить "используя"ы
  • Сделайте класс IDisposable доступным
  • Удалите кодировку URL-адреса, чтобы упростить пример.
  • Добавьте простое тестовое приспособление для демонстрации использования

Надеюсь, это поможет

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

[РЕДАКТИРОВАТЬ] Несколько лет спустя я вернулся, чтобы сказать: не делайте этого! Смотрите Что не так с XOR-шифрованием? для подробностей.

Очень простым, легким двусторонним шифрованием является шифрование XOR.

<Ол>
  • Придумай пароль. Пусть это будет mypass .
  • Преобразуйте пароль в двоичный файл (в соответствии с ASCII). Пароль становится 01101101 01111001 01110000 01100001 01110011 01110011.
  • Возьмите сообщение, которое вы хотите закодировать. Преобразуйте это также в двоичный файл.
  • Посмотрите на длину сообщения. Если длина сообщения составляет 400 байтов, превратите пароль в строку длиной 400 байтов, повторяя ее снова и снова. Он станет 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 ... (или mypassmypassmypass ... )
  • XOR сообщение с длинным паролем.
  • Отправьте результат.
  • В другой раз XOR зашифрованное сообщение с тем же паролем ( mypassmypassmypass ... ).
  • Вот ваше сообщение!
  • Я объединил то, что нашел лучшим из нескольких ответов и комментариев.

    • Случайный вектор инициализации, добавленный к криптотексту (@jbtule)
    • Используйте TransformFinalBlock() вместо MemoryStream (@RenniePet)
    • Никаких предварительно заполненных ключей, чтобы никто не копировал и не вставлял аварийную ситуацию
    • Правильная утилизация и использование шаблонов

    Код:

    /// <summary>
    /// Simple encryption/decryption using a random initialization vector
    /// and prepending it to the crypto text.
    /// </summary>
    /// <remarks>Based on multiple answers in http://stackoverflow.com/questions/165808/simple-two-way-encryption-for-c-sharp </remarks>
    public class SimpleAes : IDisposable
    {
        /// <summary>
        ///     Initialization vector length in bytes.
        /// </summary>
        private const int IvBytes = 16;
    
        /// <summary>
        ///     Must be exactly 16, 24 or 32 bytes long.
        /// </summary>
        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();
        }
    }
    

    Обновление 2015-07-18:Исправлена ошибка в методе private Encrypt() по комментариям @bpsilver и @Evereq.IV был случайно зашифрован, теперь добавляется открытым текстом, как и ожидалось с помощью функции Decrypt().

    Если вы просто хотите простое шифрование (т. е. возможно, что определенный взломщик может сломаться, но блокирует большинство случайных пользователей), просто выберите две парольные фразы одинаковой длины, скажем:

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

    и зашифруйте свои данные с ними обоими (зацикливая пароли при необходимости) (a) . Например:

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

    Кто-то ищет ваш двоичный файл, может подумать, что строка ДНК является ключом, но вряд ли он подумает, что код C - это что-то иное, чем неинициализированная память, сохраненная вместе с вашим двоичным файлом.

    <Ч>

    (a) Имейте в виду, что это очень простое шифрование и, по некоторым определениям, вообще не может считаться шифрованием (поскольку целью шифрования является < em> предотвратить несанкционированный доступ, а не просто сделать его более сложным). Хотя, конечно, даже самое надежное шифрование небезопасно, когда кто-то стоит над держателями ключей со стальной трубой.

    Как указывалось в первом предложении, это означает, что случайному злоумышленнику будет достаточно сложно двигаться дальше. Это похоже на предотвращение краж со взломом в вашем доме - вам не нужно делать его неуязвимым, вам просто нужно сделать его менее беременным, чем дом по соседству: -)

    Шифрование - это просто:как указывали другие, в Системе существуют классы.Безопасность.Пространство имен Cryptography, которое сделает всю работу за вас.Используйте их, а не какое-либо домашнее решение.

    Но расшифровать тоже несложно.Проблема, с которой вы столкнулись, заключается не в алгоритме шифрования, а в защите доступа к ключу, используемому для расшифровки.

    Я бы использовал одно из следующих решений:

    • DPAPI, использующий класс ProtectedData с областью действия CurrentUser.Это легко, так как вам не нужно беспокоиться о ключе.Данные могут быть расшифрованы только одним и тем же пользователем, поэтому не годятся для обмена данными между пользователями или машинами.

    • DPAPI, использующий класс ProtectedData с областью LocalMachine.Подходит, например, длязащита конфигурационных данных на одном защищенном сервере.Но любой, кто может войти на компьютер, может зашифровать его, так что ничего хорошего, если сервер не защищен.

    • Любой симметричный алгоритм.Обычно я использую статический SymmetricAlgorithm.Метод Create(), если мне все равно, какой алгоритм используется (на самом деле по умолчанию это Rijndael).В этом случае вам нужно каким-то образом защитить свой ключ.Например.вы можете каким-то образом запутать его и скрыть в своем коде.Но имейте в виду, что любой, кто достаточно умен, чтобы декомпилировать ваш код, скорее всего, сможет найти ключ.

    Я хотел опубликовать свое решение, поскольку ни одно из вышеперечисленных решений не является таким простым, как мое. Дайте мне знать, что вы думаете:

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

    Дополнительно

    Предполагается, что MachineKey сервера, используемого для шифрования значения, совпадает с тем, который использовался для дешифрования значения. При желании вы можете указать статический MachineKey в файле Web.config, чтобы ваше приложение могло расшифровывать / шифровать данные независимо от того, где они выполняются (например, разработка или производственный сервер). Вы можете создать статический ключ компьютера, следуя этим инструкциям .

    Использование TripleDESCryptoServiceProvider в 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);
        }
    }
    

    Пространство имен System.Security.Cryptography содержит классы TripleDESCryptoServiceProvider и RijndaelManaged

    Не забудьте добавить ссылку на сборку System.Security .

    Я изменил этот :

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

    на это:

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

    Используя встроенную библиотеку криптографии .Net, этот пример показывает, как использовать расширенный стандарт шифрования (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;
    
            }
        }
    }
    

    Я знаю, что вы сказали, что вам все равно, насколько это безопасно, но если вы выбрали DES вы также можете воспользоваться AES , это более современный метод шифрования .

    Я использовал принятый ответ по Марк Бриттингем и это мне очень помогло.Недавно мне пришлось отправить зашифрованный текст в другую организацию, и вот тут-то и возникли некоторые проблемы.OP не требует этих параметров, но поскольку это популярный вопрос, я публикую свою модификацию (Encrypt и Decrypt функции , заимствованные из здесь):

    1. Разные IV для каждого сообщения - объединяет IV байта с байтами шифрования перед получением шестнадцатеричного значения. Конечно, это конвенция, которая должна быть доведена до сведения сторон, получающих зашифрованный текст.
    2. Позволяет использовать два конструктора - один по умолчанию RijndaelManaged значения и тот, в котором могут быть указаны значения свойств (на основе взаимного соглашения между шифрующими и дешифрующими сторонами)

    Вот класс (тестовый образец в конце):

    /// <summary>
    /// 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
    /// </summary>
    public class AnotherAES : IDisposable
    {
        private RijndaelManaged rijn;
    
        /// <summary>
        /// Initialize algo with key, block size, key size, padding mode and cipher mode to be known.
        /// </summary>
        /// <param name="key">ASCII key to be used for encryption or decryption</param>
        /// <param name="blockSize">block size to use for AES algorithm. 128, 192 or 256 bits</param>
        /// <param name="keySize">key length to use for AES algorithm. 128, 192, or 256 bits</param>
        /// <param name="paddingMode"></param>
        /// <param name="cipherMode"></param>
        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;
        }
    
        /// <summary>
        /// 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
        /// </summary>
        /// <param name="key"></param>
        public AnotherAES(string key)
        {
            rijn = new RijndaelManaged();
            byte[] keyArray = Encoding.UTF8.GetBytes(key);
            rijn.Key = keyArray;
        }
    
        /// <summary>
        /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx
        /// Encrypt a string using RijndaelManaged encryptor.
        /// </summary>
        /// <param name="plainText">string to be encrypted</param>
        /// <param name="IV">initialization vector to be used by crypto algorithm</param>
        /// <returns></returns>
        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
    
        /// <summary>
        /// Based on https://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndaelmanaged(v=vs.110).aspx
        /// </summary>
        /// <param name="cipherText">bytes to be decrypted back to plaintext</param>
        /// <param name="IV">initialization vector used to encrypt the bytes</param>
        /// <returns></returns>
        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
    
        /// <summary>
        /// Generates a unique encryption vector using RijndaelManaged.GenerateIV() method
        /// </summary>
        /// <returns></returns>
        public byte[] GenerateEncryptionVector()
        {
            if (rijn == null)
                throw new ArgumentNullException("Provider not initialized");
    
            //Generate a Vector
            rijn.GenerateIV();
            return rijn.IV;
        }//end GenerateEncryptionVector
    
    
        /// <summary>
        /// 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.
        /// </summary>
        /// <param name="numBytes"></param>
        /// <returns></returns>
        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()
    
        /// <summary>
        /// Converts a string to byte array. Useful when converting back hex string which was originally formed from bytes.
        /// </summary>
        /// <param name="hex"></param>
        /// <returns></returns>
        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
    
        /// <summary>
        /// Dispose RijndaelManaged object initialized in the constructor
        /// </summary>
        public void Dispose()
        {
            if (rijn != null)
                rijn.Dispose();
        }//end Dispose()
    }//end class
    

    и..

    Вот тестовый образец:

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

    enter image description here

    Я думаю , что это самый простой вариант в мире !

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

    Тест

     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
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top