2016-08-31 69 views
1

我写了这个类,让我来加密和解密对象的JSON表示,但它不会出现如MSDN文档(这里:https://msdn.microsoft.com/en-us/library/system.security.cryptography.aesmanaged%28v=vs.95%29.aspx?f=255&MSPPError=-2147217396)的工作表明,它应该...AesEncryption似乎没有正确解密?

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

}

我写了下面的单元测试来测试这个功能了...

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

问题似乎是永无止境...

  • 出于某种原因,我得到什么似乎是在我的json输出中的解密方法中读取“var resultString = reader.ReadToEnd();”
  • 每次运行它时,输出都是不同的。
  • 当我没有附加 调试器时,它抛出了有关填充的异常,但是当我这样做时,抛出有关未能对json进行反序列化的异常。
  • 不知道为什么它似乎是阅读形式的错误配置值(但很可能无关的工作不加密)

我在做什么错?

+1

打破它的基本知识。对一个Key和IV进行硬编码,看看你是否可以在'Encrypt'和'Decrypt'方法中输入/输出相同的字符串,然后从那里开始。每次运行不同的输出意味着每个运行给我不同的键/ IV。 – Haney

+0

是的,这是我的第一个反应,硬编码的一切......它没有帮助:( – War

+0

测试数据和加密数据在哪里?您需要在加密和解密调用之前和之后转储所有输入和输出。将这些数据添加到问题中提供所有的二进制十六进制 – zaph

回答

0

好吧,我想通了,它基本上编码这里是我的问题,所以采取这一步骤进一步我去和@jbtule(感谢詹姆斯)在@https://gist.github.com/jbtule/4336842#file-aesthenhmac-cs

一把抓起示例代码已经抓住了“ AESThenHMAC”类,然后我可以写这个...

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

...这完全通过上述单元测试:)