本文介绍了在dotnet核心中使用密码和盐对字符串进行编码和解码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我一直在研究dotnet核心的简单帮助程序,该帮助程序应根据用户提供的密码(密钥)和密码对字符串进行编码和解码。

I've been working on a simple helper for dotnet core that should encode and decode a string, based on a user provided password (key) and a salt.

与完整的.NET Framework矛盾的是,dotnet内核当前没有RijndaelManaged类的实现。几乎每个C#体面的加密/解密示例都基于此类,因此对于dotnet核心来说,它是无用的。在上有很多争论。

In contradiction to the full .NET Framework, dotnet core currently does not have an implementation for the RijndaelManaged class. Pretty much every decent encrypt/decrypt sample for C# is based on this class, rendering it useless for dotnet core. There is a lot of debate on it on the CoreFX repo on GitHub.

但是,将(旧的)和-更不用说重构了-我能够酿造以下半工作示例

However, with the combination of both the (old) MSDN article on AesManaged and an article by Troy Hunt - not to mention some refactoring - I was able to brew the following semi-working example:

internal class CryptographyHelpers
{
    internal static string Decrypt(string password, string salt, string encrypted_value)
    {
        string decrypted;

        using (var aes = Aes.Create())
        {
            var keys = GetAesKeyAndIV(password, salt, aes);
            aes.Key = keys.Item1;
            aes.IV = keys.Item2;

            // create a decryptor to perform the stream transform.
            var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

            // create the streams used for encryption.
            var encrypted_bytes = ToByteArray(encrypted_value);
            using (var memory_stream = new MemoryStream(encrypted_bytes))
            {
                using (var crypto_stream = new CryptoStream(memory_stream, decryptor, CryptoStreamMode.Read))
                {
                    using (var reader = new StreamReader(crypto_stream))
                    {
                        decrypted = reader.ReadToEnd();
                    }
                }
            }
        }

        return decrypted;
    }

    internal static string Encrypt(string password, string salt, string plain_text)
    {
        string encrypted;

        using (var aes = Aes.Create())
        {
            var keys = GetAesKeyAndIV(password, salt, aes);
            aes.Key = keys.Item1;
            aes.IV = keys.Item2;

            var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

            using (var memory_stream = new MemoryStream())
            {
                using (var crypto_stream = new CryptoStream(memory_stream, encryptor, CryptoStreamMode.Write))
                {
                    using (var writer = new StreamWriter(crypto_stream))
                    {
                        writer.Write(plain_text);
                    }

                    var encrypted_bytes = memory_stream.ToArray();
                    encrypted = ToString(encrypted_bytes);
                }
            }
        }

        return encrypted;
    }

    private static byte[] ToByteArray(string input)
    {
        return Encoding.Unicode.GetBytes(input);
    }

    private static string ToString(byte[] input)
    {
        return Encoding.Unicode.GetString(input);
    }

    private static Tuple<byte[], byte[]> GetAesKeyAndIV(string password, string salt, SymmetricAlgorithm symmetricAlgorithm)
    {
        const int bits = 8;
        var key = new byte[16];
        var iv = new byte[16];

        var derive_bytes = new Rfc2898DeriveBytes(password, ToByteArray(salt));
        key = derive_bytes.GetBytes(symmetricAlgorithm.KeySize / bits);
        iv = derive_bytes.GetBytes(symmetricAlgorithm.BlockSize / bits);

        return new Tuple<byte[], byte[]>(key, iv);
    }

}

我说的是半工作示例,这意味着它可以工作... 有时。问题就在这里。当我任意运行测试时,大多数情况下都会成功。随机地,大约四分之一,它失败并显示以下消息:

I said semi-working example, which means it works... sometimes. And there lies the problem. When I run my test arbitrarily, it succeeds most of the time. Randomly, about one out of four times, it fails with the following message:

这似乎是一个unicode问题,但是将助手中的Encoding.Unicode更改为Encoding.UTF8会导致错误:

It looks like a unicode problem, but changing the Encoding.Unicode in the helpers to Encoding.UTF8, leads to the error:

将编码更改为Encoding。 ASCII导致以下错误:

Changing the encoding to Encoding.ASCII leads to the following error:

我正在使用的测试是:

[Fact]
public void Decrypt_Should_Decode_An_Encrypted_String()
{
    // arrange
    var key = Guid.NewGuid().ToString();
    var salt = Guid.NewGuid().ToString();
    var original_value = "lorem ipsum dom dolor sit amet";
    var encrypted_value = CryptographyHelpers.Encrypt(key, salt, original_value);

    // act
    var target = CryptographyHelpers.Decrypt(key, salt, encrypted_value);

    // assert
    target.Should().NotBeNullOrEmpty();
    target.Should().Be(original_value);
}

因此,我的主要问题是:为什么我的执行力(测试)有时会失败?

So, my primary question is: why does my imlementation (test) sometimes fail?

我绝对不是密码学方面的专家,但是从高层上我知道一些基本概念。此外,还发布了类似的问题,但这是唯一的问题答案停留在概念上,缺乏具体的实现。

I am definitely not an expert on cryptography, but on a high level am aware of some basic concepts. Also, a similar question "How to use Rijndael encryption with a .Net Core class library?" was posted, but the only answer stays on a conceptual level, lacking concrete implementation.

关于这是否是一个足够好的实现的任何提示和争论也将不胜感激。

Any tips and arguments as to if this is a 'good enough' implementation would also be very much appreciated.

谢谢!

推荐答案

您的问题与密码学无关而是由这对函数引起的

Your problem has nothing to do with cryptography and instead is caused by this pair of functions

private static byte[] ToByteArray(string input)
{
    return Encoding.Unicode.GetBytes(input);
}

private static string ToString(byte[] input)
{
    return Encoding.Unicode.GetString(input);
}

不允许调用 GetString 在任意字节数组上,如果这样做会导致信息丢失。您需要使用允许任意字节数组的编码,例如Base64:

You are not allowed to call GetString on arbitrary byte arrays, you will cause a loss of information if you do. You need to use a encoding that allows for arbitrary byte arrays, for example Base64:

private static byte[] ToByteArray(string input)
{
    return Convert.FromBase64String(input);
}

private static string ToString(byte[] input)
{
    return Convert.ToBase64String(input);
}

这篇关于在dotnet核心中使用密码和盐对字符串进行编码和解码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-06 17:24