2010-12-31 2 views
1

HMAC-SHA256 체크섬을 확인해야하는 응용 프로그램을 작성 중입니다.C#의 해시 다이제스트/배열 비교

static bool VerifyIntegrity(string secret, string checksum, string data) 
    { 
     // Verify HMAC-SHA256 Checksum 
     byte[] key = System.Text.Encoding.UTF8.GetBytes(secret); 
     byte[] value = System.Text.Encoding.UTF8.GetBytes(data); 
     byte[] checksum_bytes = System.Text.Encoding.UTF8.GetBytes(checksum); 
     using (var hmac = new HMACSHA256(key)) 
     { 
      byte[] expected_bytes = hmac.ComputeHash(value); 
      return checksum_bytes.SequenceEqual(expected_bytes); 
     } 
    } 

나는이 timingattacks에 취약 것을 알고 : 나는 현재이 코드는 다음과 같이 보입니다.

표준 라이브러리에 메시지 요약 비교 기능이 있습니까? 나는 내 자신의 시간을 강화 된 비교 방법을 쓸 수 있다는 것을 알았지 만, 나는 이것이 이미 다른 곳에 구현되었다고 믿어야 만한다.

답변

2

편집 : 원래 대답은 다음과 같습니다 - ... IMO 읽기,하지만 타이밍 공격에 대해 여전히 가치가 당신이 참조

페이지는 컴파일러 최적화에 대한 몇 가지 흥미로운 점을 제공합니다.

: 당신은 두 바이트 배열은 같은 길이 될 것입니다 알고있는 점을 감안하면 이 같은 뭔가를 시도 할 수 있습니다 (길이가 다른 경우 체크섬의 크기 가정, 특히 비밀되지 않고 즉시 반환 할 수 있습니다)
public static bool CompareArraysExhaustively(byte[] first, byte[] second) 
{ 
    if (first.Length != second.Length) 
    { 
     return false; 
    } 
    bool ret = true; 
    for (int i = 0; i < first.Length; i++) 
    { 
     ret = ret & (first[i] == second[i]); 
    } 
    return ret; 
} 

이제는 모든 입력에 동일한 시간이 걸리지 않습니다. 두 배열이 둘 다 L1 캐시에있는 경우 주 메모리에서 페치해야하는 경우보다 빠를 가능성이 큽니다. 그러나 보안 측면에서 중요한 문제가 발생하지는 않을 것으로 생각됩니다.

괜찮습니까? 누가 알아. 서로 다른 프로세서와 다른 버전의 CLR은 두 피연산자에 따라 & 작업에 서로 다른 시간이 걸릴 수 있습니다. 기본적으로 이것은 참조한 페이지의 결론과 동일합니다. 이는 휴대용 방식으로 얻는 것만 큼 좋지만 실행하려고하는 모든 플랫폼에서 유효성 검사가 필요하다는 것입니다.

적어도 위 코드는 비교적 간단한 조작 만 사용합니다. 어떤 경우에는 부적절한 최적화 작업이있을 수 있으므로 개인적으로 LINQ 작업을 사용하지 않아야합니다. 나는이 경우에 이 될 것이라고 생각하지 않거나 패배하기 쉽습니다. 적어도 은 그들에 대해을 생각해야합니다. 거기에 대한 :)


원래 대답을

걱정 "전용"JIT 컴파일러 및 프로세서 최적화를 떠나 - 위의 코드와 함께, 소스 코드와 IL 사이에 적어도 상당히 밀접한 관계가있다 이 중 하나의 중요한 문제점 : 체크섬을 제공하려면 UTF-8로 인코딩 된 형식이 체크섬과 동일한 문자열이 있어야합니다. UTF-8로 인코딩 된 텍스트를 나타내지 않는 많은 바이트 시퀀스가 ​​있습니다. 기본적으로 UTF-8을 사용하여 텍스트로 임의의 바이너리 데이터를 인코딩하려는 것은 좋지 않습니다.

는 Base64로, 다른 한편으로는,이를 위해 기본적으로 설계입니다 : 한편

static bool VerifyIntegrity(string secret, string checksum, string data) 
{ 
    // Verify HMAC-SHA256 Checksum 
    byte[] key = Encoding.UTF8.GetBytes(secret); 
    byte[] value = Encoding.UTF8.GetBytes(data); 
    byte[] checksumBytes = Convert.FromBase64String(checksum); 
    using (var hmac = new HMACSHA256(key)) 
    { 
     byte[] expectedBytes = hmac.ComputeHash(value); 
     return checksumBytes.SequenceEqual(expectedBytes); 
    } 
} 

대신 바이트 배열에 SequenceEqual를 사용하여, 당신 수 Base64로 인코딩 실제 해시, 일치하는지 확인하십시오 :

static bool VerifyIntegrity(string secret, string checksum, string data) 
{ 
    // Verify HMAC-SHA256 Checksum 
    byte[] key = Encoding.UTF8.GetBytes(secret); 
    byte[] value = Encoding.UTF8.GetBytes(data); 
    using (var hmac = new HMACSHA256(key)) 
    { 
     return checksum == Convert.ToBase64String(hmac.ComputeHash(value)); 
    } 
} 

프레임 워크 내에서 더 잘 알지 못합니다. 처음에는 동일한 길이를 검사하는 배열 (또는 일반 ICollection<T> 구현)에 대해 특수화 된 SequenceEqual 연산자를 작성하는 것이 그리 어렵지는 않지만 해시가 짧다는 점을 고려하면 걱정하지 않을 것입니다. 당신이 SequenceEqual의 타이밍에 대해 걱정하는 경우

+0

유효 포인트가 있지만 타이밍 공격 각도가 완전히 누락 된 것 같습니다. –

+0

@Henk : "나는 이것이 약하다는 것을 알고 있지만, 나는 그 부분을 무시하고있다"고 오해한다. 편집 할 것입니다. –

+0

@ 존 : 내 질문에 대한 철저한 답변을 주셔서 감사합니다. 기본적인 프로파일 링을했는데 Windows 7/Server 2008에서 'CompareArraysExhaustively'가 완벽하게 수행됩니다. –

0

어떻게 타이밍 공격에 취약합니까? 유효하거나 유효하지 않은 다이제스트의 경우 코드가 동일한 시간 동안 작동합니다. 그리고 digest/check digest를 계산하는 것이 가장 쉬운 방법 인 것처럼 보입니다.

+2

나는 'SequenceEqual'은 해시 초기에 차이가 발생하면 더 빨리 false를 반환하고 나중에 다른 경우에는 더 오랜 시간이 걸린다는 점을 우려한다고 생각합니다. – MerickOWA

+0

좋아요, 그는 (i = 0; i

+2

기사를 확인하십시오. 마이크로 초의 차이라도 추적 할 수 있으므로 위의 코드로도 공격이 가능할 수 있습니다. –

2

, 당신은 항상 이런 식으로 대체 할 수 :

checksum_bytes.Zip(expected_bytes, (a,b) => a == b).Aggregate(true, (a,r) => a && r); 

이 SequenceEquals과 같은 결과를 반환하지만 항상 전에 대답이 주어진 모든 요소를 ​​확인 타이밍 공격을 통해 어떤 것도 드러 낼 기회가 적습니다.