2016-09-02 5 views
1

나는 문자열을 안전하게 전달하기 위해 간단한 dto를 직렬화하고 암호화하려고합니다..Net에서 AES + HMAC 암호화

이것에 관해서 물을 때 대부분의 사람들이 Encrypt and decrypt a string에 나를 가리키는 것처럼 보입니다. @jbtule은 가능한 두 가지 해결책으로 정말 상세한 답변을 제공 할 시간을 가졌습니다.

내가 그의 요점 https://gist.github.com/jbtule/4336842#file-aesthenhmac-cs ("AESThenHMAC.cs"라는 이름의 파일에서 두 번째 예제의 사본을 가지고 내 프로젝트에서 그것을 뒀다.

내가 그 때 마무리하는 좋은 방법이 될 거라고 생각하고 빨리이 솔루션을 테스트하지만 나는 그것이 작동 얻을 수없는 것

누군가가 내가 여기서 잘못하고 있어요 무엇인지 설명 할 수

여기 내 래퍼 라운드 @의 jbtule의 코드입니다 :.?

using Newtonsoft.Json; 
using System.Text; 

namespace Core.Data 
{ 
    public class AesCrypto<T> : ICrypto<T> 
    { 
     public string Encrypt(T source, string salt) 
     { 
      var enc = Encoding.Unicode; 
      var rawData = JsonConvert.SerializeObject(source); 
      return enc.GetString(AESThenHMAC.SimpleEncryptWithPassword(enc.GetBytes(rawData), salt)); 
     } 

     public T Decrypt(string source, string salt) 
     { 
      var enc = Encoding.Unicode; 
      var decryptedBytes = AESThenHMAC.SimpleDecryptWithPassword(enc.GetBytes(source), salt); 
      return JsonConvert.DeserializeObject<T>(enc.GetString(decryptedBytes)); 
     } 
    } 
} 
,개

그리고 간단한 단위 테스트 확인이 모든 작품 : 어떤 이유

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

    var saltBytes = new byte[32]; 
    new Random().NextBytes(saltBytes); 
    var testSalt = Encoding.Unicode.GetString(saltBytes); 

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

jbtule의 요점 라인 (261)에서 수행 된 검사가 0

에 값 255을 비교하기 때문에 암호 해독 방법은 null을 반환

이것은 .NET 형식 (. AesEncryption doesn't appear to decrypt right? 참조)과 직접 대화하려는 나의 시도에서 따랐으며,이 시점에서 일관되게 작동하는 솔루션이 필요합니다.

+1

모든 바이트 쌍이 유효한 유니 코드 문자로 매핑되는 것은 아닙니다. 'GetString()'이 유효한'char'가 아닌 바이트 쌍을 만날 때 [fallback strategy] (https://msdn.microsoft.com/en-us/library/ms404377(v=vs.110)) .aspx # Anchor_3)를 사용하여 쌍을 유효한 문자로 바꿉니다. 즉, 데이터를 잃어버린 것입니다. 대신 ['Convert.ToBase64String()'] (https://msdn.microsoft.com/en-us/library/dhx0d524(v=vs.110) .aspx)과 같은 것을 사용하십시오. base64 인코딩에 대해 잘 모르겠지만 엔트로피를 잃을 수 있습니까? 나는 확실히 말할 보안에 대해 충분히 모른다. – dbc

+0

흠 ... 여기에 유니 코드가 문제가 될 것이라고 생각하지 않았습니다 ... 좋은 호칭이라 생각합니다. 다시 고칠 수 있는지 확인하십시오. – War

+1

[Pbkdf2를 사용하여 완벽한 암호 해싱 솔루션] (http://stackoverflow.com/documentation/c%23/2774/hash-functions/15470/complete-password-hashing-solution-using-pbkdf2)을 확인하십시오. 전체 예제의 맨 아래에는'ByteConverter' 유틸리티 클래스가 있습니다.이 클래스를 사용하면'byte [] '를 16 진수 문자열로 변환하고 역수로 변환 할 수 있습니다. 이렇게하면 문자열 변환 프로세스에서 손실되는 것을 걱정할 필요없이 바이트 배열의 실제 문자열 표현이 보장됩니다. 엄격한 바이트 배열 비교 (문자열 변환을 사용하지 않음)를 수행하려면 'CompareHashes'메서드 (동일한 예제)를 사용할 수도 있습니다. – Igor

답변

0

@dbc 덕택에 ... 나는 내가 모르는 것을 발견하지 못했다!

using Newtonsoft.Json; 
using System; 
using System.Text; 

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

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

소스 유형이 'T'인 fance를 얻은 다음 코드에서 UTF-8로 인코딩 된 데이터를 사용합니다. – zaph

+0

문제점을 설명 할 수 있습니까? –

+0

보안 및 검증 가능한 방식으로 응용 프로그램간에 데이터를 보낼 수있는 다용도 암호화 시스템이 필요합니다. 예 : 위의 예에서는 요청시 서명을 나타내는 간단한 DTO 객체를 정의한 다음 Json API에 대한 원격 호출을 수행하여이 객체의 암호를 해독하여 원격 끝점에서 확인할 수있는 사용자 정의 헤더로 출력 문자열을 추가합니다 . AES를 사용하면 암호화 할 수 있지만 HMAC를 추가하면 데이터가 해독 될 때 데이터가 변조되지 않았다는 확인도 추가됩니다. – War