2013-10-30 2 views
3

SHA-512 알고리즘을 사용하여 SQL Server 2008에서 암호 해시 및 암호 해독 솔루션을 구현하려고합니다. 이 솔루션은 Michael Coles의 저서 "Expert SQL Server 2008 Encryption"을 기반으로합니다. 그의 예제를 기반으로 Visual Studio 2010 (C#의 .NET 3.5)에서 프로젝트를 빌드하고 SQL Server 2008에 배포 할 수 있습니다 (아래 코드 참조).SQL Server 2008의 암호 해시 CLR

using System; 
using System.Data; 
using System.Data.SqlClient; 
using System.Data.SqlTypes; 
using Microsoft.SqlServer.Server; 
using System.Security.Cryptography; 

namespace Apress.Samples 
{ 
    public partial class CustomEncryption 
    { 
    [Microsoft.SqlServer.Server.SqlFunction 
    (
     IsDeterministic = true, 
     DataAccess = DataAccessKind.None 
    )] 
    public static SqlBytes SaltedHash 
    (
     SqlString Algorithm, 
     [SqlFacet(MaxSize = -1)] SqlBytes PlainText, 
     SqlBytes Salt 
    ) 
    { 
     // Return NULL if any of the parameters is NULL 
     if (Algorithm.IsNull || PlainText.IsNull || Salt.IsNull) 
      return SqlBytes.Null; 

     // Determine which algorithm to use 
     bool HashDefined = true; 
     HashAlgorithm Hash = null; 
     switch (Algorithm.Value.ToUpper()) 
     { 
      case "SHA256": 
       Hash = new SHA256Managed(); 
       break; 

      case "SHA384": 
       Hash = new SHA384Managed(); 
       break; 

      case "SHA512": 
       Hash = new SHA512Managed(); 
       break; 

      default: 
       HashDefined = false; 
       break; 
     } 
     if (!HashDefined) 
      throw new Exception 
       ("Unsupported hash algorithm - use SHA256, SHA384 or SHA512"); 

     // Combine the plaintext with the salt 
     byte[] PlainTextWithSalt = new byte[PlainText.Length + Salt.Length]; 
     for (long i = 0; i < Salt.Length; i++) 
      PlainTextWithSalt[i] = Salt[i]; 
     for (long i = Salt.Length; i < PlainText.Length; i++) 
      PlainTextWithSalt[i] = PlainText.Value[i - Salt.Length]; 

     // Generate the hash and return the result 
     byte[] HashBytes = Hash.ComputeHash(PlainTextWithSalt); 
     return new SqlBytes(HashBytes); 
    } 
} 
} 

아래 코드를 사용하여 SQL에서 테스트를 수행하면 각 알고리즘에 대해 예상대로 해시가 생성됩니다.

DECLARE @plaintext varchar(15); 
SET @plaintext = 'ABCDEFGHIJ'; 

DECLARE @salt varbinary(16); 
SET @salt = Crypt_Gen_Random(16); 

DECLARE @sha256 varbinary(32) 
DECLARE @sha384 varbinary(48) 
DECLARE @sha512 varbinary(64) 

SELECT @sha256 = dbo.SaltedHash('SHA256', CAST(@plaintext AS varbinary(max)), @salt); 
SELECT @sha384 = dbo.SaltedHash('SHA384', CAST(@plaintext AS varbinary(max)), @salt); 
SELECT @sha512 = dbo.SaltedHash('SHA512', CAST(@plaintext AS varbinary(max)), @salt); 

SELECT 'SHA-256' AS algorithm, @sha256 AS hash 
UNION ALL 
SELECT 'SHA-384', @sha384 
UNION ALL 
SELECT 'SHA-512', @sha512; 

난 내가 사용자 레코드에 저장되는 소금 값을 검색하고 SaltedHash 기능, 그것은 것까지 함께 전달할 필요가 있으리라 믿고있어 로그인을, 검증을 위해 이것을 사용하고 싶습니다 해시 된 값을 리턴하십시오. 거기에서, 나는 함수에 의해 반환 된 해시 된 값을 사용자 레코드에 저장된 해쉬 된 값과 비교할 것이다.

내가 겪고있는 문제는 평문 ('ABCDEFGHIJ')와 함께 하드 코딩 된 소금 값 ('0x0E5ECC235FF6BD7337FFDDE5799D4EEA')을 전달하여 테스트 할 때 해시 된 값 (예 : 해시 암호 비교)을 시뮬레이트하는 경우입니다. 동일한 하드 코딩 된 소금 값을 사용하여 ('1234567890')의 일반 텍스트 값을 제공하면 정확히 동일한 해시 값을 반환합니다. 사실, 10 문자의 일반 텍스트 값은 동일한 해시 값을 반환합니다.

DECLARE @plaintext varchar(15); 
SET @plaintext = 'ABCDE12345'; 

DECLARE @salt varbinary(16); 
SET @salt = 0x0E5ECC235FF6BD7337FFDDE5799D4EEA; // Hardcoded salt value! 

SELECT @salt 

DECLARE @sha256 varbinary(32) 
DECLARE @sha384 varbinary(48) 
DECLARE @sha512 varbinary(64) 

SELECT @sha256 = dbo.SaltedHash('SHA256', CAST(@plaintext AS varbinary(max)), @salt); 
SELECT @sha384 = dbo.SaltedHash('SHA384', CAST(@plaintext AS varbinary(max)), @salt); 
SELECT @sha512 = dbo.SaltedHash('SHA512', CAST(@plaintext AS varbinary(max)), @salt); 

SELECT 'SHA-256' AS algorithm, @sha256 AS hash 
UNION ALL 
SELECT 'SHA-384', @sha384 
UNION ALL 
SELECT 'SHA-512', @sha512; 

"평문과 소금을 결합하는"코드에 문제가 있다고 가정하고 있지만 확실하지 않습니다.

이 문제를 해결하는 방법에 대한 아이디어가 있습니까?

+0

소금이 최종 솔루션에 하드 코드 된 경우 소금이 아닙니다. 그것은 [Pepper] (http://security.stackexchange.com/questions/3272/password-hashing-add-salt-pepper-or-is-salt-enough) 일 것이며, 소금은 암호마다 고유하므로 일반적으로 cyphertext의 bytearray의 앞이나 뒤쪽에있는 다음 열에 소금을 보관하거나 병합하십시오. –

+0

'Pepper'에 익숙하지 않아서 고맙습니다. 내 의도는 당신이 제안한대로 비밀 번호 당 고유 한 소금을 만드는 것입니다. – vanexellent

답변

2

예 배열 배열에 오류가 발생했습니다. PlainText의 마지막 Salt.Length 바이트를 대상 배열에 복사하지 마십시오. 다음은 원래 코드의 수정 된 버전입니다. 이주의하는 Array.Copy

byte[] PlainTextWithSalt = new byte[PlainText.Length + Salt.Length]; 
Array.Copy(Salt, PlainTextWithSalt, Salt.Length); 
Array.Copy(PlainText, PlainTextWithSalt, Salt.Length, PlainText.Length); 

한가지를 사용하여 할 수있는 많은 쉽습니다 그러나 수행하는 데 필요한 모든 것은 PlainText.Length + Salt.Length

// Combine the plaintext with the salt 
byte[] PlainTextWithSalt = new byte[PlainText.Length + Salt.Length]; 
for (long i = 0; i < Salt.Length; i++) 
    PlainTextWithSalt[i] = Salt[i]; 
for (long i = Salt.Length; i < PlainText.Length + Salt.Length; i++) 
    PlainTextWithSalt[i] = PlainText.Value[i - Salt.Length]; 

까지 갈 i 요구를합니다. 암호를 안전하게 처리하는 것이 좋습니다. 그러나 that is only half the battle, 해시를 만들어야합니다. SLOW. 일반적으로 bcrypt 또는 PBKDF2과 같은 함수로 수행되며,이 함수는 소금과 암호를 혼합하여 관리합니다. 또한 해시 반복 횟수를 암호에 대해 설정할 수 있습니다. 대개 큰 수를 선택하면 속도가 느린 경우 최종 시스템에서 허용되는만큼 큰 번호).

+0

수정 된 코드를 적용하여 현재 작동하고 있음을 확인했습니다. 숙제도 고마워. CLR/.NET SHA2 방법을 사용하기로 결정한 이유는 더 널리 채택 된 솔루션 인 것처럼 보였기 때문입니다. 하지만 bcrypt가 내가 투자 할 시간이기도하다.bcrypt의 '튜닝'부분은 매력적인 기능처럼 보입니다. – vanexellent

+0

@vanexellent PBKDF2에는 [ItterationCount] (http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.iterationcount.aspx) 속성을 통해 튜닝 팩터가 내장되어 있습니다 (그러나 현대 하드웨어에서 알고리즘의 의미있는 감속을 얻기 위해 숫자에 '> 10000'을 사용하고 싶을 것입니다.) 튜너 블 작업 요소 사용에 대한 좋은 점은 더 빠른 하드웨어를 얻고 해시를 단지 다시 해시 할 필요가있을 때입니다. 다음 번에 사용자가 로그인 할 때 더 큰 요인으로, 마지막으로 사용한 작업 요소를 해시 및 소금으로 저장하는 것만으로도 충분합니다. –

+0

감사합니다. 알고리즘에 대한 연구를 해본 결과, 해당 알고리즘이 유용하다는 것을 알았 기 때문에 기쁘게 생각합니다. SQL 2008 (.NET 3.5)에서 사용되었는데, 이는 우리가 지금 당장 사용하고있는 버전입니다. 도움을 감사하십시오! – vanexellent