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

时间:2021-09-22 17:20:56

How do we use Rijndael encryption in a .Net Core class library? (Not a .Net Framework Class Library) We need to create a shared .Net Core library for use in multiple projects and need to implement Encrypt and Decrypt methods that use the same Rijndael encryption across the projects.

我们如何在.Net Core类库中使用Rijndael加密? (不是.Net Framework类库)我们需要创建一个共享的.Net Core库,用于多个项目,并且需要实现在项目中使用相同Rijndael加密的Encrypt和Decrypt方法。

We are currently using:

我们目前正在使用:

  • VS Enterprise 2015
  • VS企业版2015

  • c#
  • .Net Core Class Library
  • .Net核心类库

  • .NETStandard, Version=v1.6 reference
  • .NETStandard,Version = v1.6 reference

It appears that the implementation of Rijndael and AES is missing from the .Net Core 1.0 release...it seems to only include the base classes. How do we get a .Net Core implementation of Rijndael or AES encryption added as a reference to a new .Net Core Class Library project?

似乎.Net Core 1.0版本中缺少Rijndael和AES的实现...它似乎只包括基类。我们如何获得Rijndael或AES加密的.Net Core实现作为新的.Net核心类库项目的参考?

Here is the Encrypt method that works in .Net Framework 4.5.2:

以下是在.Net Framework 4.5.2中使用的Encrypt方法:

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

2 个解决方案

#1


21  

The difference (in .NET) between Rijndael and AES is that Rijndael allows the block size to change, but AES does not. Since RijndaelManaged's default block size is the same as the AES block size (128 bit / 16 byte) you are, in fact, using AES.

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

Instead of instantiating the implementation type by name, just use the factory (Aes.Create()). That works in both .NET Core and .NET Framework.

不要按名称实例化实现类型,只需使用工厂(Aes.Create())。这适用于.NET Core和.NET Framework。

Other things worth mentioning:

其他值得一提的事情:

  • All SymmetricAlgorithm instances are IDisposable, you should use them in a using statement.
  • 所有SymmetricAlgorithm实例都是IDisposable,您应该在using语句中使用它们。

  • All ICryptoTransform instances (such as your incorrectly named desEncryptor) are IDisposable, you should use them in a using statement.
  • 所有ICryptoTransform实例(例如您错误命名的desEncryptor)都是IDisposable,您应该在using语句中使用它们。

  • ISO10126 padding is not available in .NET Core 1.0. If you need to be compatible with existing streams you can apply the padding yourself and specify PaddingMode.None. Otherwise, PKCS7 is more standard.
  • .NET Core 1.0中不提供ISO10126填充。如果需要与现有流兼容,可以自己应用填充并指定PaddingMode.None。否则,PKCS7更标准。

  • Your AES key isn't very random, since it comes from an ASCII string (lots of values won't be valid).
    • Base64 at least has full value range
    • Base64至少具有完整的值范围

    • PBKDF2 (Password-Based Key Derivation Function 2) via the Rfc2898DeriveBytes class allows for shared-string-secret in, predictable noise out.
    • PBKDF2(基于密码的密钥派生函数2)通过Rfc2898DeriveBytes类允许共享字符串秘密,可预测的噪声输出。

    • KeyAgreement is in general better, but neither ECDH nor classic DH are available in .NET Core 1.0.
    • KeyAgreement通常更好,但是.NET Core 1.0中既没有ECDH也没有经典DH。

  • 您的AES密钥不是非常随机,因为它来自ASCII字符串(许多值无效)。 Base64至少具有全值范围PBKDF2(基于密码的密钥派生函数2)通过Rfc2898DeriveBytes类允许共享字符串秘密,可预测的噪声输出。 KeyAgreement通常更好,但是.NET Core 1.0中既没有ECDH也没有经典DH。

  • Usually the encryptor should let a random IV be calculated (call aes.GenerateIV() if using the same object for multiple operations) and present it with the ciphertext. So encrypt takes a key and plaintext and produces a ciphertext and IV. Decrypt takes (key, IV, ciphertext) and produces plaintext.
  • 通常,加密器应该计算随机IV(如果对多个操作使用相同的对象,则调用aes.GenerateIV())并将其与密文一起呈现。因此,加密需要密钥和明文,并产生密文和IV。 Decrypt采用(密钥,IV,密文)并生成明文。

#2


0  

If you just want to encrypt/decrypt stuff, avoid using Rijndael directly as asp.net core has some much nicer wrappers that are much easier to use and more likely to be properly secure by default. It is known as DataProtection.

如果你只是想加密/解密东西,请避免直接使用Rijndael,因为asp.net核心有一些更好的包装器,它们更容易使用,并且默认情况下更可能是正确安全的。它被称为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}");

See the data protection docs for more information

有关更多信息,请参阅数据保护文档

#1


21  

The difference (in .NET) between Rijndael and AES is that Rijndael allows the block size to change, but AES does not. Since RijndaelManaged's default block size is the same as the AES block size (128 bit / 16 byte) you are, in fact, using AES.

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

Instead of instantiating the implementation type by name, just use the factory (Aes.Create()). That works in both .NET Core and .NET Framework.

不要按名称实例化实现类型,只需使用工厂(Aes.Create())。这适用于.NET Core和.NET Framework。

Other things worth mentioning:

其他值得一提的事情:

  • All SymmetricAlgorithm instances are IDisposable, you should use them in a using statement.
  • 所有SymmetricAlgorithm实例都是IDisposable,您应该在using语句中使用它们。

  • All ICryptoTransform instances (such as your incorrectly named desEncryptor) are IDisposable, you should use them in a using statement.
  • 所有ICryptoTransform实例(例如您错误命名的desEncryptor)都是IDisposable,您应该在using语句中使用它们。

  • ISO10126 padding is not available in .NET Core 1.0. If you need to be compatible with existing streams you can apply the padding yourself and specify PaddingMode.None. Otherwise, PKCS7 is more standard.
  • .NET Core 1.0中不提供ISO10126填充。如果需要与现有流兼容,可以自己应用填充并指定PaddingMode.None。否则,PKCS7更标准。

  • Your AES key isn't very random, since it comes from an ASCII string (lots of values won't be valid).
    • Base64 at least has full value range
    • Base64至少具有完整的值范围

    • PBKDF2 (Password-Based Key Derivation Function 2) via the Rfc2898DeriveBytes class allows for shared-string-secret in, predictable noise out.
    • PBKDF2(基于密码的密钥派生函数2)通过Rfc2898DeriveBytes类允许共享字符串秘密,可预测的噪声输出。

    • KeyAgreement is in general better, but neither ECDH nor classic DH are available in .NET Core 1.0.
    • KeyAgreement通常更好,但是.NET Core 1.0中既没有ECDH也没有经典DH。

  • 您的AES密钥不是非常随机,因为它来自ASCII字符串(许多值无效)。 Base64至少具有全值范围PBKDF2(基于密码的密钥派生函数2)通过Rfc2898DeriveBytes类允许共享字符串秘密,可预测的噪声输出。 KeyAgreement通常更好,但是.NET Core 1.0中既没有ECDH也没有经典DH。

  • Usually the encryptor should let a random IV be calculated (call aes.GenerateIV() if using the same object for multiple operations) and present it with the ciphertext. So encrypt takes a key and plaintext and produces a ciphertext and IV. Decrypt takes (key, IV, ciphertext) and produces plaintext.
  • 通常,加密器应该计算随机IV(如果对多个操作使用相同的对象,则调用aes.GenerateIV())并将其与密文一起呈现。因此,加密需要密钥和明文,并产生密文和IV。 Decrypt采用(密钥,IV,密文)并生成明文。

#2


0  

If you just want to encrypt/decrypt stuff, avoid using Rijndael directly as asp.net core has some much nicer wrappers that are much easier to use and more likely to be properly secure by default. It is known as DataProtection.

如果你只是想加密/解密东西,请避免直接使用Rijndael,因为asp.net核心有一些更好的包装器,它们更容易使用,并且默认情况下更可能是正确安全的。它被称为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}");

See the data protection docs for more information

有关更多信息,请参阅数据保护文档