AesEncryption doesn't appear to decrypt right?

五迷三道 提交于 2019-12-11 07:54:29

问题


I wrote this class to allow me to encrypt and decrypt the json representation of objects but it doesn't appear to work as the MSDN documentation (here: https://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged%28v=vs.95%29.aspx?f=255&MSPPError=-2147217396) suggests it should ...

using Newtonsoft.Json;
using System;
using System.Configuration;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Web.Configuration;

namespace Core.Data
{
    public class AesCrypto<T> : ICrypto<T>
    {
    string DecryptionKey { get { return ((MachineKeySection)ConfigurationManager.GetSection("system.web/machineKey")).DecryptionKey; } }

    public string Encrypt(T source, string salt)
    {
        var sourceString = JsonConvert.SerializeObject(source);

        using (var aes = new AesManaged())
        {
            aes.Padding = PaddingMode.PKCS7;
            aes.GenerateIV();

            using (var stream = new MemoryStream())
            {
                var deriveBytes = new Rfc2898DeriveBytes(DecryptionKey, Encoding.Unicode.GetBytes(salt));
                aes.Key = deriveBytes.GetBytes(128 / 8);
                stream.Write(BitConverter.GetBytes(aes.IV.Length), 0, sizeof(int));
                stream.Write(aes.IV, 0, aes.IV.Length);

                using (var cs = new CryptoStream(stream, aes.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    byte[] rawPlaintext = Encoding.Unicode.GetBytes(sourceString);
                    cs.Write(rawPlaintext, 0, rawPlaintext.Length);
                    cs.FlushFinalBlock();

                    stream.Seek(0, SeekOrigin.Begin);

                    using (var reader = new StreamReader(stream, Encoding.Unicode))
                        return reader.ReadToEnd();
                }
            }
        }
    }

    public T Decrypt(string sourceString, string salt)
    {
        using (Aes aes = new AesManaged())
        {
            aes.Padding = PaddingMode.PKCS7;
            var deriveBytes = new Rfc2898DeriveBytes(DecryptionKey, Encoding.Unicode.GetBytes(salt));
            aes.Key = deriveBytes.GetBytes(128 / 8);

            using (var stream = new MemoryStream(Encoding.Unicode.GetBytes(sourceString)))
            {
                stream.Seek(0, SeekOrigin.Begin);

                // Get the initialization vector from the encrypted stream
                aes.IV = ReadIV(stream);

                using (var reader = new StreamReader(new CryptoStream(stream, aes.CreateDecryptor(aes.Key, aes.IV), CryptoStreamMode.Read), Encoding.Unicode))
                {
                    var resultString = reader.ReadToEnd();
                    return JsonConvert.DeserializeObject<T>(resultString);
                }
            }
        }
    }

    byte[] ReadIV(Stream s)
    {
        byte[] rawLength = new byte[sizeof(int)];
        if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
        {
            throw new SystemException("Stream did not contain properly formatted byte array");
        }

        byte[] buffer = new byte[BitConverter.ToInt32(rawLength, 0)];
        if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
        {
            throw new SystemException("Did not read byte array properly");
        }

        return buffer;
    }
}

}

I wrote the following unit test to test this functionality out ...

using Core.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;

namespace Core.Tests
{
    [TestClass]
    public class CryptoTests
    {
        class EncryptableObject
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public DateTimeOffset When { get; set; }
        }

        [TestMethod]
        public void TestAesCrypto()
        {
            var testInput = new EncryptableObject { Id = 123, Name = "Victim", When = DateTimeOffset.UtcNow };
            var crypto = new AesCrypto<EncryptableObject>();

            var testSalt = "testtest";

            var magicString = crypto.Encrypt(testInput, testSalt);
            var testOutput = crypto.Decrypt(magicString, testSalt);

            Assert.AreEqual(testInput.Id, testOutput.Id);
            Assert.AreEqual(testInput.Name, testOutput.Name);
            Assert.AreEqual(testInput.When, testOutput.When);
        }
    }
}

Problems seem to be endless ...

  • For some reason I get what seems to be chineese characters in my json output in the decrypt method on the line that reads "var resultString = reader.ReadToEnd();"
  • The output is different each time I run it.
  • It throws an exception about padding when I don't attach the debugger, but throws an exception about failing to deserialise the json when I do.
  • Not sure why it appears to be reading form the wrong config value (but that's likely unrelated to the encryption not working)

What am I doing wrong?


回答1:


Ok I figured out it was basically encoding that was my problem here, so taking this step further I went and grabbed the code from the examples by @jbtule (thanks James) over @ https://gist.github.com/jbtule/4336842#file-aesthenhmac-cs

Having grabbed the "AESThenHMAC" class I could then write this ...

public class AesCrypto<T> : ICrypto<T>
{
    public string Encrypt(T source, string key)
    {
        var e = Encoding.UTF8;
        var rawData = e.GetBytes(JsonConvert.SerializeObject(source));
        var cipherData = AESThenHMAC.SimpleEncryptWithPassword(rawData, key);
        return Convert.ToBase64String(cipherData);
    }

    public T Decrypt(string source, string key)
    {
        var e = Encoding.UTF8;
        var decryptedBytes = AESThenHMAC.SimpleDecryptWithPassword(Convert.FromBase64String(source), key);
        return JsonConvert.DeserializeObject<T>(e.GetString(decryptedBytes));
    }
}

... which passes the above unit test perfectly :)



来源:https://stackoverflow.com/questions/39255395/aesencryption-doesnt-appear-to-decrypt-right

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!