Шифрование и расшифровка строки в C# [дубликат]

этот вопрос уже есть ответ здесь:

  • шифровать и расшифровывать строку в C#? 23 ответов

каков самый современный (лучший) способ удовлетворения следующего в C#?

string encryptedString = SomeStaticClass.Encrypt(sourceString);

string decryptedString = SomeStaticClass.Decrypt(encryptedString);

но с минимумом суеты с участием солей, ключей, возни с байтом [] и т. д.

гуглил и смущен тем, что я нахожу (вы можете увидеть список подобных так Qs, чтобы увидеть, что это обманчивый вопрос).

7 ответов


обновление 23 / Dec / 2015: поскольку этот ответ, похоже, получает много upvotes, я обновил его, чтобы исправить глупые ошибки и в целом улучшить код на основе комментариев и отзывов. Список конкретных улучшений см. В конце поста.

как говорили другие люди, криптография не проста, поэтому лучше избегать "сворачивания собственного" алгоритма шифрования.

вы можете, однако, "свернуть свой собственный" класс обертки вокруг чего-то вроде встроенный RijndaelManaged класс криптографии.

Rijndael-это алгоритмическое имя текущего Расширенный Стандарт Шифрования, поэтому вы, безусловно, используете алгоритм, который можно считать "лучшей практикой".

на RijndaelManaged класс действительно обычно требует от вас" возиться " с байтовыми массивами, солями, ключами, векторами инициализации и т. д. но это именно та деталь, которая может быть несколько абстрагированные в твой класс "обертки".

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

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

в "сила" использования этого происходит от использования RijndaelManaged класс для шифрования для вас, наряду с использованием Rfc2898DeriveBytes


using System.IO;
using System.Text;
using System.Security.Cryptography;

public static class EncryptionHelper
{
    public static string Encrypt(string clearText)
    {
        string EncryptionKey = "abc123";
        byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(clearBytes, 0, clearBytes.Length);
                    cs.Close();
                }
                clearText = Convert.ToBase64String(ms.ToArray());
            }
        }
        return clearText;
    }
    public static string Decrypt(string cipherText)
    {
        string EncryptionKey = "abc123";
        cipherText = cipherText.Replace(" ", "+");
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
            encryptor.Key = pdb.GetBytes(32);
            encryptor.IV = pdb.GetBytes(16);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(cipherBytes, 0, cipherBytes.Length);
                    cs.Close();
                }
                cipherText = Encoding.Unicode.GetString(ms.ToArray());
            }
        }
        return cipherText;
    }
}

попробовать этот класс:

public class DataEncryptor
{
    TripleDESCryptoServiceProvider symm;

    #region Factory
    public DataEncryptor()
    {
        this.symm = new TripleDESCryptoServiceProvider();
        this.symm.Padding = PaddingMode.PKCS7;
    }
    public DataEncryptor(TripleDESCryptoServiceProvider keys)
    {
        this.symm = keys;
    }

    public DataEncryptor(byte[] key, byte[] iv)
    {
        this.symm = new TripleDESCryptoServiceProvider();
        this.symm.Padding = PaddingMode.PKCS7;
        this.symm.Key = key;
        this.symm.IV = iv;
    }

    #endregion

    #region Properties
    public TripleDESCryptoServiceProvider Algorithm
    {
        get { return symm; }
        set { symm = value; }
    }
    public byte[] Key
    {
        get { return symm.Key; }
        set { symm.Key = value; }
    }
    public byte[] IV
    {
        get { return symm.IV; }
        set { symm.IV = value; }
    }

    #endregion

    #region Crypto

    public byte[] Encrypt(byte[] data) { return Encrypt(data, data.Length); }
    public byte[] Encrypt(byte[] data, int length)
    {
        try
        {
            // Create a MemoryStream.
            var ms = new MemoryStream();

            // Create a CryptoStream using the MemoryStream 
            // and the passed key and initialization vector (IV).
            var cs = new CryptoStream(ms,
                symm.CreateEncryptor(symm.Key, symm.IV),
                CryptoStreamMode.Write);

            // Write the byte array to the crypto stream and flush it.
            cs.Write(data, 0, length);
            cs.FlushFinalBlock();

            // Get an array of bytes from the 
            // MemoryStream that holds the 
            // encrypted data.
            byte[] ret = ms.ToArray();

            // Close the streams.
            cs.Close();
            ms.Close();

            // Return the encrypted buffer.
            return ret;
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
        }
        return null;
    }

    public string EncryptString(string text)
    {
        return Convert.ToBase64String(Encrypt(Encoding.UTF8.GetBytes(text)));
    }

    public byte[] Decrypt(byte[] data) { return Decrypt(data, data.Length); }
    public byte[] Decrypt(byte[] data, int length)
    {
        try
        {
            // Create a new MemoryStream using the passed 
            // array of encrypted data.
            MemoryStream ms = new MemoryStream(data);

            // Create a CryptoStream using the MemoryStream 
            // and the passed key and initialization vector (IV).
            CryptoStream cs = new CryptoStream(ms,
                symm.CreateDecryptor(symm.Key, symm.IV),
                CryptoStreamMode.Read);

            // Create buffer to hold the decrypted data.
            byte[] result = new byte[length];

            // Read the decrypted data out of the crypto stream
            // and place it into the temporary buffer.
            cs.Read(result, 0, result.Length);
            return result;
        }
        catch (CryptographicException ex)
        {
            Console.WriteLine("A cryptographic error occured: {0}", ex.Message);
        }
        return null;
    }

    public string DecryptString(string data)
    {
        return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(data))).TrimEnd('');
    }

    #endregion

}

и используйте его так:

string message="A very secret message here.";
DataEncryptor keys=new DataEncryptor();
string encr=keys.EncryptString(message);

// later
string actual=keys.DecryptString(encr);

Если вам нужно сохранить пароль в памяти и вы хотите, чтобы он был зашифрован, вы должны использовать SecureString:

http://msdn.microsoft.com/en-us/library/system.security.securestring.aspx

для более общего использования я бы использовал алгоритм, одобренный FIPS, такой как Advanced Encryption Standard, ранее известный как Rijndael. См. эту страницу для реализации пример:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx


вы можете искать ProtectedData класс, который шифрует данные, используя учетные данные пользователя.


если вы нацелены ASP.NET ядро, которое не поддерживает RijndaelManaged тем не менее, вы можете использовать IDataProtectionProvider.

во-первых, настройте приложение для использования защиты данных:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDataProtection();
    }
    // ...
}

тогда вы сможете ввести IDataProtectionProvider экземпляр и использовать его для шифрования/дешифрования данных:

public class MyService : IService
{
    private const string Purpose = "my protection purpose";
    private readonly IDataProtectionProvider _provider;

    public MyService(IDataProtectionProvider provider)
    {
        _provider = provider;
    }

    public string Encrypt(string plainText)
    {
        var protector = _provider.CreateProtector(Purpose);
        return protector.Protect(plainText);
    }

    public string Decrypt(string cipherText)
    {
        var protector = _provider.CreateProtector(Purpose);
        return protector.Unprotect(cipherText);
    }
}

посмотреть в этой статье для получения более подробной информации.


самый простой способ, который я видел, чтобы сделать шифрование через RSA

Проверьте MSDN на нем: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx

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