2016-08-31 70 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)); 
    } 
} 

...這完全通過上述單元測試:)