2014-09-17 6 views
6

저는 완전히 암호화에 익숙하지 만 배우고 있습니다. 저는 온라인에서 저의 연구 결과를 여러 가지 방법으로 결합 해 해시, 소금, 키 스트레칭 및 관련 데이터의 비교/변환을 처리하기위한 자체 클래스를 만들었습니다.소금 & 해시 코드에서 SHA-512를 Rfc2898DeriveBytes와 함께 사용하려면 어떻게해야합니까?

암호화를위한 내장 .NET 라이브러리를 조사한 결과, 내가 가지고있는 것은 여전히 ​​SHA-1이라는 것을 발견했습니다. 하지만 해시 프로세스를 여러 번 반복 할 때가 나쁘지는 않다는 결론에 도달했습니다. 그 맞습니까?

그러나 더 강력한 SHA-512로 시작하려면 어떻게해야합니까? 아래 코드에서 어떻게 구현할 수 있습니까? 미리 감사드립니다.

using System; 
using System.Runtime.InteropServices; 
using System.Security; 
using System.Security.Cryptography; 

public class CryptoSaltAndHash 
{ 
    private string strHash; 
    private string strSalt; 
    public const int SaltSizeInBytes = 128; 
    public const int HashSizeInBytes = 1024; 
    public const int Iterations = 3000; 

    public string Hash { get { return strHash; } } 
    public string Salt { get { return strSalt; } } 

    public CryptoSaltAndHash(SecureString ThisPassword) 
    { 
     byte[] bytesSalt = new byte[SaltSizeInBytes]; 
     using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider()) 
     { 
      crypto.GetBytes(bytesSalt); 
     } 
     strSalt = Convert.ToBase64String(bytesSalt); 
     strHash = ComputeHash(strSalt, ThisPassword); 
    } 

    public static string ComputeHash(string ThisSalt, SecureString ThisPassword) 
    { 
     byte[] bytesSalt = Convert.FromBase64String(ThisSalt); 
     Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(
      convertSecureStringToString(ThisPassword), bytesSalt, Iterations); 
     using (pbkdf2) 
     { 
      return Convert.ToBase64String(pbkdf2.GetBytes(HashSizeInBytes)); 
     } 
    } 

    public static bool Verify(string ThisSalt, string ThisHash, SecureString ThisPassword) 
    { 
     if (slowEquals(getBytes(ThisHash), getBytes(ComputeHash(ThisSalt, ThisPassword)))) 
     { 
      return true; 
     } 
     return false; 
    } 

    private static string convertSecureStringToString(SecureString MySecureString) 
    { 
     IntPtr ptr = IntPtr.Zero; 
     try 
     { 
      ptr = Marshal.SecureStringToGlobalAllocUnicode(MySecureString); 
      return Marshal.PtrToStringUni(ptr); 
     } 
     finally 
     { 
      Marshal.ZeroFreeGlobalAllocUnicode(ptr); 
     } 
    } 

    private static bool slowEquals(byte[] A, byte[] B) 
    { 
     int intDiff = A.Length^B.Length; 
     for (int i = 0; i < A.Length && i < B.Length; i++) 
     { 
      intDiff |= A[i]^B[i]; 
     } 
     return intDiff == 0; 
    } 

    private static byte[] getBytes(string MyString) 
    { 
     byte[] b = new byte[MyString.Length * sizeof(char)]; 
     System.Buffer.BlockCopy(MyString.ToCharArray(), 0, b, 0, b.Length); 
     return b; 
    } 
} 

참고 : 많은 연습을 https://crackstation.net/hashing-security.htm에서 참조했습니다. slowEquals 비교 방법은 분기를 방지하여 실행 시간을 표준화하는 것입니다. SecureString의 사용법은이 클래스와 웹 애플리케이션 내의 다른 클래스와 페이지 사이에 암호화 된 암호 형식을 전달하는 것입니다. 이 사이트는 HTTPS를 통해 진행되지만, 여전히 사유가 될 때까지 가능한 한 보안을 유지하기 위해 추가 마일을 나가는 것이 좋습니다.

내 코드에서 키 문자열을 128 바이트 (가끔은 더 커지더라도 괜찮습니다), 해시 크기를 1KB로, 반복 횟수를 3,000으로 설정했습니다. 일반적인 64 바이트 소금, 512 바이트 해시 및 1,000 회 또는 2,000 회 반복보다 약간 크지 만 로그인 속도와 앱 성능은 매우 낮은 우선 순위입니다.

생각하십니까?

+0

코드 검토에 관한 비슷한 질문 [보안 암호 해싱] (http://codereview.stackexchange.com/questions/32856/secure-password-hashing) – CodesInChaos

답변

5

질문에 대답 : "SecurityDriven.NET"책의 무료 코드 샘플을 다운로드하십시오. PBKDF2 클래스를 찾으십시오.이 클래스는 HMAC이됩니다. HMACSHA512 공장을 이용할 수 있습니다.

암호 작성을 처음 접했기 때문에 CodesInChaos가 만든 점을 완전히 이해할 수 있도록 책을 읽으시기 바랍니다.

+0

감사합니다. 이러한 예제에서는 .NET 4.5를 사용하지만 .NET 4.0에서는 사용합니다. 그러나 그들은 최소한의 변화로 양쪽 모두를 위해 일해야합니다. 이러한 예제는 필요한 암호화 클래스를 참조합니다. http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha512%28v=vs.100%29.aspx –

8
  1. 3000 반복이 매우 낮습니다. 10000조차도 낮습니다. 그러나 공격자가 자주 로그인하여 서버를 위험에 빠뜨리는 위험에 대비하여 추가 반복의 보안 이득을 가중시켜야합니다. 이렇게하면 로그인 할 때마다 값 비싼 해시가 트리거됩니다.
  2. 128 비트/16 바이트보다 큰 소금에 포인트가 없습니다. 소금은 독특한 것이어야합니다.
  3. 해시 크기가 기본 크기 (SHA-1의 경우 20 바이트)보다 크면 방어자의 성능은 저하되지만 공격자의 성능은 저하됩니다. 이는 반복 횟수를 줄일 수 있음을 의미하므로 실제로 보안을 약화시킵니다.

    예를 들어, 3000 바이트의 해시가있는 1024 바이트 해시와 동일한 비용으로 156000 개의 반복으로 20 바이트의 해시를 제공 할 수 있으며, 이는 균열이 52 배 더 비쌉니다.

  4. SHA-2를 사용하려면 완전히 다른 PBKDF2 구현이 필요하며 .net에 포함 된 것은 SHA-1을 사용하기 위해 하드 코드됩니다.

    제 3 자 라이브러리를 사용하는 것을 괴롭히면 GPU 기반 공격자에 비해 훨씬 강력하므로 bcrypt 라이브러리를 사용하고 싶습니다.

  5. 소금 관리를 Create/Verify 함수 내에서 처리하는 대신 호출자에게 푸시하기 때문에 API가 사용하기가 어렵습니다.

  6. SecureString을 사용하고 String으로 변환하는 것은 바보입니다. 이것은 처음에 SecureString을 사용하는 모든 지점을 방해합니다.

    개인적으로 일반적인 응용 프로그램에서는 SecureString으로 신경 쓰지 않을 것입니다.암호가 String에 저장되지 않으며 더 이상 필요하지 않으면 변경 가능한 저장소에서 항상 지워지는 것을 확인하는 포괄적 인 전체 스택 보안 검토와 결합하면 가치가 있습니다.

  7. 암호/소금을 인스턴스 변수에 저장하지 않습니다. 관련 기능에 국한하십시오. 인스턴스 변수 (예 : 반복 횟수)에만 구성을 저장합니다.

  8. SHA-1은 암호 학적으로 약화되지만 공격에 의해 충돌이 발생합니다. 암호 해싱 충돌은 관련성이 없으므로 걱정되는 것은 첫 번째 사전 이미지 공격입니다. SHA-1은 여전히 ​​그 점에서 꽤 강하다.

    SHA-512의 주된 장점은 암호 연산이 강력하다는 것만은 아니지만 (비록 그렇긴하지만) 수비자가 64 비트 Intel CPU를 사용하기 때문에 64 비트 산술 비용이 방어기보다 높다는 것입니다. 64 비트 산술.

+0

훌륭한 조언, 정말 고마워요! 코드에서 문자열로 변환하지 않으면 SecureString만을 사용하는 것을 기억합니다. 사용하기가 어색한 내 API에 대해서는 잘 작동하는 것 같습니다. 클래스를 인스턴스화하여 소금을 만들고 has 또는 이전에 만든 해시를 확인하기 위해 정적으로 호출합니다. 아무 관리도 거기 발신자에 밀었다. 그러나 제 질문은 4 번 지점을 중심으로 진행됩니다. 그 제안에 대해 더 자세히 설명하고 .NET 환경에서 어떻게 구현되는지 (예 : 추천 할 SHA-2 라이브러리를 선택하십시오)? 다시 한 번 감사드립니다! –

+0

PBKDF2-HMAC-SHA-2의 C# 구현을 조사해 본적이 없으므로 실제로 알지 못합니다. 나는 bouncycastle이 그것을 지원한다고 생각할 것이다. 개인적으로 필자는 bcrypt.net 및 다른 bcrypt 구현을 평가하려고합니다. – CodesInChaos