加密.NET Core中的字符串

dkn*_*ack 24 c# encryption .net-core

我想使用密钥加密.NET Core中的字符串.我有一个客户端/服务器方案,并希望加密客户端上的字符串,将其发送到服务器并解密它.

由于.NET Core仍处于早期阶段(例如Rijndael尚未推出),我有哪些选择?

bar*_*njs 31

你真的不应该在.NET中使用Rijndael/RijndaelManaged.如果您使用的BlockSize值为128(这是默认值),那么您正在使用AES,正如我在类似问题中所解释的那样.

.NET Core中提供的对称加密选项包括:

  • AES(System.Security.Cryptography.Aes.Create())
  • 3DES(System.Security.Cryptography.TripleDES.Create())

对于非对称加密

  • RSA(System.Security.Cryptography.RSA.Create())

特别是在.NET Core上,工厂是最好的方法,因为它们会返回一个对象,该对象可以在当前正在执行的操作系统上运行.例如,RSACng是一种公共类型,但仅适用于Windows; 和RSAOpenSsl是一种公共类型,但仅在Linux和macOS上受支持.

  • 这是与 AES 相关的教程 https://code-maze.com/csharp-string-encryption-decryption/ (3认同)

Mar*_*cus 24

已经有了答案,但我认为我们可以提供更简单的解决方案.

如果您只是想保护您的数据,那么在.NET Core中就可以实现这一功能,从而使您免于加密的麻烦; DataProtectionProvider.

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection(); //Add this
    [..]
    services.AddMvc();
}
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以指定Microsoft.AspNetCore.DataProtection用于加密和验证的算法(使用),如下所示:

services.AddDataProtection()
       .UseCryptographicAlgorithms(new AuthenticatedEncryptionSettings()
       {
           EncryptionAlgorithm = EncryptionAlgorithm.AES_256_GCM,
           ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
       });
Run Code Online (Sandbox Code Playgroud)

然后使用服务加密/解密:

public class CipherService : ICipherService
{
    private readonly IDataProtectionProvider _dataProtectionProvider;
    private const string Key = "my-very-long-key-of-no-exact-size";

    public CipherService(IDataProtectionProvider dataProtectionProvider)
    {
        _dataProtectionProvider = dataProtectionProvider;
    }

    public string Encrypt(string input)
    {
        var protector = _dataProtectionProvider.CreateProtector(Key);
        return protector.Protect(input);
    }

    public string Decrypt(string cipherText)
    {
        var protector = _dataProtectionProvider.CreateProtector(Key);
        return protector.Unprotect(cipherText);
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑 正如下面的评论中提到的那样,理解使用像这样的DataProtectionProvider只能在存储在本地磁盘上的密钥的同一台机器上工作可能是个好主意.

  • "我非常长的钥匙 - 没有精确尺寸"`不是一个惊悚的钥匙,只是保护者的唯一名称.默认情况下,实际密钥作为文件存储在磁盘上(因此请注意是否在Web场中) (13认同)
  • 值得注意的是,这里的密钥存储在机器上(默认情况下),因此它只能由加密它的机器解密.如果您需要能够在应用程序的多个实例或不同服务(例如单点登录)中解密密钥,请使用分布式DataProtection(如Microsoft.AspNetCore.DataProtection.Redis`)来共享密钥. (12认同)
  • 您应该编辑您的答案,因为当他们在多个实例和一个实例上部署此代码并且密钥将不同时,某人会有糟糕的一天. (4认同)
  • Microsoft建议不要将其用于长期受保护的数据。 (4认同)
  • 这是否也能用于`.NET MVC`? (2认同)
  • DataProtection 密钥也可以使用 [EF Core DbContext](https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/implementation/key-storage-providers?view =aspnetcore-5.0&tabs=visual-studio#entity-framework-core),然后它应该与加密和解密数据的多个实例一起使用。 (2认同)

dhc*_*cgn 14

这是一个没有身份验证的简单示例:

var text = "Hello World";
var buffer = Encoding.UTF8.GetBytes(text);

var iv = GetRandomData(128);
var keyAes = GetRandomData(256);


byte[] result;
using (var aes = Aes.Create())
{
    aes.Key = keyAes;
    aes.IV = iv;

    using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
    using (var resultStream = new MemoryStream())
    {
        using (var aesStream = new CryptoStream(resultStream, encryptor, CryptoStreamMode.Write))
        using (var plainStream = new MemoryStream(buffer))
        {
            plainStream.CopyTo(aesStream);
        }

        result = resultStream.ToArray();
    }
}
Run Code Online (Sandbox Code Playgroud)

用于密钥生成:

private static byte[] GetRandomData(int bits)
{
    var result = new byte[bits / 8];
    RandomNumberGenerator.Create().GetBytes(result);
    return result;
}
Run Code Online (Sandbox Code Playgroud)


iss*_*ss0 7

我有一种不同的方法,我想用一个密钥加密一个字符串并获得一个加扰的字符串,我可以再次用同一密钥解密。请参阅以下扩展方法:

    public static string Encrypt(this string text, string key)
    {
        if (string.IsNullOrEmpty(key))
            throw new ArgumentException("Key must have valid value.", nameof(key));
        if (string.IsNullOrEmpty(text))
            throw new ArgumentException("The text must have valid value.", nameof(text));

        var buffer = Encoding.UTF8.GetBytes(text);
        var hash = new SHA512CryptoServiceProvider();
        var aesKey = new byte[24];
        Buffer.BlockCopy(hash.ComputeHash(Encoding.UTF8.GetBytes(key)), 0, aesKey, 0, 24);

        using (var aes = Aes.Create())
        {
            if (aes == null)
                throw new ArgumentException("Parameter must not be null.", nameof(aes));

            aes.Key = aesKey;

            using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
            using (var resultStream = new MemoryStream())
            {
                using (var aesStream = new CryptoStream(resultStream, encryptor, CryptoStreamMode.Write))
                using (var plainStream = new MemoryStream(buffer))
                {
                    plainStream.CopyTo(aesStream);
                }

                var result = resultStream.ToArray();
                var combined = new byte[aes.IV.Length + result.Length];
                Array.ConstrainedCopy(aes.IV, 0, combined, 0, aes.IV.Length);
                Array.ConstrainedCopy(result, 0, combined, aes.IV.Length, result.Length);

                return Convert.ToBase64String(combined);
            }
        }
    }

    public static string Decrypt(this string encryptedText, string key)
    {
        if (string.IsNullOrEmpty(key))
            throw new ArgumentException("Key must have valid value.", nameof(key));
        if (string.IsNullOrEmpty(encryptedText))
            throw new ArgumentException("The encrypted text must have valid value.", nameof(encryptedText));

        var combined = Convert.FromBase64String(encryptedText);
        var buffer = new byte[combined.Length];
        var hash = new SHA512CryptoServiceProvider();
        var aesKey = new byte[24];
        Buffer.BlockCopy(hash.ComputeHash(Encoding.UTF8.GetBytes(key)), 0, aesKey, 0, 24);

        using (var aes = Aes.Create())
        {
            if (aes == null)
                throw new ArgumentException("Parameter must not be null.", nameof(aes));

            aes.Key = aesKey;

            var iv = new byte[aes.IV.Length];
            var ciphertext = new byte[buffer.Length - iv.Length];

            Array.ConstrainedCopy(combined, 0, iv, 0, iv.Length);
            Array.ConstrainedCopy(combined, iv.Length, ciphertext, 0, ciphertext.Length);

            aes.IV = iv;

            using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
            using (var resultStream = new MemoryStream())
            {
                using (var aesStream = new CryptoStream(resultStream, decryptor, CryptoStreamMode.Write))
                using (var plainStream = new MemoryStream(ciphertext))
                {
                    plainStream.CopyTo(aesStream);
                }

                return Encoding.UTF8.GetString(resultStream.ToArray());
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 生成的密文不是确定性的,具有相同密钥和明文的Encrypt()的不同运行会生成不同的密文 (2认同)

Web*_*ine 5

ASP.NET Core 应用程序默认启用数据保护系统。您甚至不需要在 StartUp 方法中执行任何操作,除非您想重新配置默认密钥存储位置或密钥的生命周期。在这种情况下,您将在 ConfigureServices 方法中执行以下操作:

services.ConfigureDataProtection(dp =>
    {
        dp.PersistKeysToFileSystem(new DirectoryInfo(@"c:\keys"));
        dp.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
    });
Run Code Online (Sandbox Code Playgroud)

由于数据保护系统默认位于应用程序的服务集合中,因此可以通过依赖注入使其可用。以下是如何将 IDataProtectionProvider 注入控制器,然后使用它在控制器的构造函数中创建 IDataProtector 的实例:

public class HomeController : Controller
{
    IDataProtector _protector;

    public HomeController(IDataProtectionProvider provider)
    {
        _protector = provider.CreateProtector(GetType().FullName);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以调用保护程序来加密内容,如下所示:

public IActionResult Index()
{
    var model = _service.GetAll().Select(c => new ContractViewModel {
        Id = _protector.Protect(c.Id.ToString()),
        Name = c.Name }).ToList();
    return View(model);
}
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助 :)