2016-08-05 60 views
13

我想使用密钥加密.NET核心中的字符串。我有一个客户端/服务器方案,并希望加密客户端上的字符串,将其发送到服务器并对其进行解密。由于.NET Core仍处于早期阶段(例如Rijndael尚未推出),我有什么选择?使用.NET核心加密字符串

+2

根据评论[这里](http://stackoverflow.com/questions/38333722/how-to-use-rijndael-encryption-with-a-net-core-class -library-not-net-framewo),它正在版本1.1中实现。直到那时,你可以使用AES [如图所示](http://stackoverflow.com/questions/35912849/rijndael-in-class-library-package-not-avaiable-for-dotnet5-4) – keyboardP

回答

16

你真的不应该在.NET中使用Rijndael/RijndaelManaged。如果您使用的BlockSize值为128(这是默认值),那么您使用AES,因为我的explained in a similar question

在.NET核心可用的对称加密选项是:

  • 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上受支持。

+0

我正在工作与.Net核心与System.Security.Cryptograph,它看起来Aes“创建()”功能缺失。我在我的project.json中包含了“System.Security.Cryptography.Algorithms”:“4.3.0”,我是否缺少参考?这是下面的编译错误。 错误CS0426 \t'Aes'类型中不存在类型名称'Create' – phanf

+0

@phanf https://apisof.net/catalog/System.Security.Cryptography.Aes.Create()表示它存在于所有.NET Core的版本。你可能使用了不同类型的相同名称? – bartonjs

+0

也不能在这个包中的各个类上找到create()方法。最新的macnetosx dotnet核心。 – kevinc

9

下面是一个简单的示例认证:

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

密钥生成:

private static byte[] GetRandomData(int bits) 
{ 
    var result = new byte[bits/8]; 
    RandomNumberGenerator.Create().GetBytes(result); 
    return result; 
} 
+0

如果你的byte []足够小,你也可以避免使用流,并使用encryptor.TransformFinalBlock(buffer,0,buffer.Length) –

+0

@JimW没错。我很好奇,你为什么要这样? –

+0

代码少,创建对象少,不喜欢什么? –

3

已经有一个答案,这一点,但我认为我们可以提供一个简单的解决方案。

如果您只是想要保护保护您的数据,那么在.NET Core中有一个实现可以让您免于加密的烦恼; DataProtectionProvider

Startup.cs

public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddDataProtection(); //Add this 
    [..] 
    services.AddMvc(); 
} 

如果你想,就可以指定算法(使用Microsoft.AspNetCore.DataProtection)用于加密和验证,像这样:

services.AddDataProtection() 
     .UseCryptographicAlgorithms(new AuthenticatedEncryptionSettings() 
     { 
      EncryptionAlgorithm = EncryptionAlgorithm.AES_256_GCM, 
      ValidationAlgorithm = ValidationAlgorithm.HMACSHA256 
     }); 

然后加密/解密使用这样的服务:

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); 
    } 
} 
+0

这是否也可以在'.NET MVC'中使用? – NoReceipt4Panda

+3

值得注意的是这里的密钥存储在机器上(默认情况下),所以它只能被加密的机器解密。如果您需要能够在应用程序或不同服务的多个实例上进行解密(如单点登录),请使用分布式DataProtection(如“Microsoft.AspNetCore.DataProtection.Redis”)来共享密钥。 – hofnarwillie

+1

''我的非常长尺寸不准确的尺寸“'不是一个excrpytion键,只是保护器的唯一名称。实际的密钥在默认情况下以文件形式存储在磁盘上(因此请注意,如果在Web场中) – alastairtree

1

数据pr ASP.NET Core应用程序默认启用保护系统。除非要重新配置默认密钥存储位置或密钥的生存时间,否则您甚至不需要在StartUp方法中执行任何操作。在这种情况下,你会做你的ConfigureServices方法如下:

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

因为数据保护系统,在应用程序的服务集合在默认情况下,它可以制成通过依赖注入提供。这里是你如何能注入IDataProtectionProvider到控制器中,然后使用它在控制器的构造函数创建一个IDataProtector的一个实例:

public class HomeController : Controller 
{ 
    IDataProtector _protector; 

    public HomeController(IDataProtectionProvider provider) 
    { 
     _protector = provider.CreateProtector(GetType().FullName); 
    } 
} 

然后,您可以调用保护,以这样的加密内容:

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

我希望这可以帮助:)