如何在.Net Core类库中使用Rijndael加密?(不是.Net Framework)

17
我们如何在 .Net Core 类库中使用 Rijndael 加密?(不是 .Net Framework 类库)我们需要创建一个共享的 .Net Core 库,用于多个项目,并需要实现加密和解密方法以在这些项目中使用相同的 Rijndael 加密。
我们目前使用:
- VS Enterprise 2015 - C# - .Net Core 类库 - .NETStandard,版本=v1.6 引用
看起来 .Net Core 1.0 版本缺少 Rijndael 和 AES 的实现...它似乎只包括基础类。如何将 .Net Core 实现的 Rijndael 或 AES 加密添加为新的 .Net Core 类库项目的引用?
下面是在 .Net Framework 4.5.2 中工作的加密方法:
public static string Encrypt(string valueToEncrypt, string symmetricKey, string initializationVector)
{
    string returnValue = valueToEncrypt;

    var aes = new System.Security.Cryptography.RijndaelManaged();
    try
    {
        aes.Key = ASCIIEncoding.ASCII.GetBytes(symmetricKey);
        aes.IV = ASCIIEncoding.ASCII.GetBytes(initializationVector);
        aes.Mode = CipherMode.CBC;
        aes.Padding = PaddingMode.ISO10126;

        var desEncrypter = aes.CreateEncryptor();
        var buffer = ASCIIEncoding.ASCII.GetBytes(valueToEncrypt);

        returnValue = Convert.ToBase64String(desEncrypter.TransformFinalBlock(buffer, 0, buffer.Length));
    }
    catch (Exception)
    {
        returnValue = string.Empty;
    }

    return returnValue;
}

1
.NET Core 有什么问题?是缺少了某个库吗? - Nate Barbettini
2
似乎这已经在1.1版本的路线图上了:https://github.com/dotnet/corefx/issues/9984 - Eli Arbel
正确的Nate,主要问题似乎是在当前版本的.Net Core中,密码学引用中缺少Rijndael实现...只有基类抽象实现。 - Ensunder
  1. ISO10126已被撤销,PKCS#7可能是更好的选择,并且实际上似乎符合ISO10126规范。
  2. 最好使用随机iv,否则相同的消息将具有相同的加密字节。通常,iv是从CPRNG创建并附加到加密数据中以供解密时使用。
  3. 使用字符串作为加密不是特别安全的,可能会导致密钥长度问题。最好使用诸如PBKFD1之类的密钥派生函数。还有盲目希望密码将是ACIII而不是其他编码,例如unicode。
- zaph
2个回答

29

.NET中Rijndael和AES的区别在于Rijndael允许块大小改变,而AES不允许。由于RijndaelManaged的默认块大小与AES块大小相同(128位/16字节),实际上您正在使用AES。

不要通过名称实例化实现类型,只需使用工厂(Aes.Create())。在.NET Core和.NET Framework中都可以使用。

其他值得注意的事项:

  • 所有SymmetricAlgorithm实例都是可处理的,应在using语句中使用它们。
  • 所有ICryptoTransform实例(例如您错误命名的desEncryptor)都是可处理的,应在using语句中使用它们。
  • 在.NET Core 1.0中不支持ISO10126填充。如果需要与现有流兼容,则可以自己应用填充并指定PaddingMode.None。否则,PKCS7更加标准。
  • 您的AES密钥不太随机,因为它来自ASCII字符串(许多值将无效)。
    • Base64至少具有完整的值范围
    • 通过Rfc2898DeriveBytes类的PBKDF2(基于密码的密钥派生函数2),可以输入共享字符串密钥并生成可预测噪声
    • KeyAgreement通常更好,但.NET Core 1.0中既不支持ECDH也不支持经典DH。
  • 通常加密器应计算一个随机的IV(如果使用同一对象进行多个操作,请调用aes.GenerateIV()),并将其与密文一起呈现。因此,加密使用密钥和明文生成密文和IV。解密使用(密钥、IV、密文)并生成明文。

bartonjs:抱歉如果这是一个愚蠢的问题,但我已经尝试搜索如何做到这一点...我该如何手动应用ISO10126填充?我们确实需要与现有流兼容。 - Ensunder
将数组扩展为块对齐(如果已经是,则添加另一个块),并按照https://en.wikipedia.org/wiki/Padding_(cryptography)#ISO_10126进行填充。如果您正在使用流,可以将其排空到数组中,或者制作一个自定义的ICryptoTramsform来包装当前的ICryptoTransform,并在TransformFinalBlock中应用/删除填充。(当然,自定义转换也适用于直接字节)。 - bartonjs
当使用CFB模式且无填充时,由Aes创建的CreateEncryptor不能具有InputBlockSize == 1。RijndaelManaged没有这个问题。 - Paul Chen
我有使用块大小为256加密的东西。我该如何解密它? - Joe Phillips

4
如果你只是想加密/解密东西,避免直接使用Rijndael,因为asp.net core有一些更好的包装器,更容易使用,并且更有可能默认情况下安全。它被称为DataProtection。
using Microsoft.AspNetCore.DataProtection;

// During startup add DP
serviceCollection.AddDataProtection();

...

// the 'provider' parameter is provided by DI
public MyClass(IDataProtectionProvider provider)
{
    _protector = provider.CreateProtector("Contoso.MyClass.v1");
}

...

// protect the payload
string protectedPayload = _protector.Protect(input);
Console.WriteLine($"Protect returned: {protectedPayload}");

...

// unprotect the payload
string unprotectedPayload = _protector.Unprotect(protectedPayload);
Console.WriteLine($"Unprotect returned: {unprotectedPayload}");

请查看数据保护文档以获取更多信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接