C #의 해시 및 솔트 비밀번호


178

난 그냥에 DavidHayden의 기사 중 하나를 통해가는 해싱 사용자의 암호 .

정말 그가 달성하려는 것을 얻을 수 없습니다.

그의 코드는 다음과 같습니다.

private static string CreateSalt(int size)
{
    //Generate a cryptographic random number.
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    byte[] buff = new byte[size];
    rng.GetBytes(buff);

    // Return a Base64 string representation of the random number.
    return Convert.ToBase64String(buff);
}

private static string CreatePasswordHash(string pwd, string salt)
{
    string saltAndPwd = String.Concat(pwd, salt);
    string hashedPwd =
        FormsAuthentication.HashPasswordForStoringInConfigFile(
        saltAndPwd, "sha1");
    return hashedPwd;
}

암호를 해싱하고 소금을 추가하는 다른 C # 방법이 있습니까?



6
소금을 생성하는 첫 번째 방법으로 크기에 무엇을 전달해야합니까?
셰인 르블랑

6
링크가 끊어졌습니다.
osmanraifgunes

@ShaneLeBlanc 함수 출력이있는 비트 수 이상이어야합니다. SHA1은 암호화 등급이 아니므로 적어도 SHA256256 비트 또는 32 바이트를 출력하는을 사용해야 합니다. 그러나 각 base64 문자는 6 비트를 인코딩하고 256은 전체적으로 6으로 나눌 수 없으므로 256 비트는 기본 64로 쉽게 변환 할 수 없습니다. 따라서 6 (base64의 경우)과 8 (바이트의 비트의 경우)의 공통 분모가 필요합니다. 256 비트 이상 (264 바이트 또는 33 바이트) TLDR : 33을 사용하십시오.
VSO

답변:


248

실제로 이것은 문자열 변환과 함께 이상합니다. 멤버쉽 공급자가 구성 파일에 넣습니다. 해시 및 솔트는 이진 Blob이므로 텍스트 파일에 저장하지 않는 한 문자열로 변환 할 필요가 없습니다.

내 책, Beginning ASP.NET Security (오, 마지막으로 책을 포주 변명)에서 다음을 수행합니다.

static byte[] GenerateSaltedHash(byte[] plainText, byte[] salt)
{
  HashAlgorithm algorithm = new SHA256Managed();

  byte[] plainTextWithSaltBytes = 
    new byte[plainText.Length + salt.Length];

  for (int i = 0; i < plainText.Length; i++)
  {
    plainTextWithSaltBytes[i] = plainText[i];
  }
  for (int i = 0; i < salt.Length; i++)
  {
    plainTextWithSaltBytes[plainText.Length + i] = salt[i];
  }

  return algorithm.ComputeHash(plainTextWithSaltBytes);            
}

소금 생성은 문제의 예와 같습니다. 을 사용하여 텍스트를 바이트 배열로 변환 할 수 있습니다 Encoding.UTF8.GetBytes(string). 당신은 그것의 문자열 표현으로 해시를 변환해야하는 경우 사용할 수있는 Convert.ToBase64StringConvert.FromBase64String 그것을 다시 변환 할 수 있습니다.

바이트 배열에는 항등 연산자를 사용할 수 없으며 참조를 확인하므로 두 배열을 반복하여 각 바이트를 검사해야합니다.

public static bool CompareByteArrays(byte[] array1, byte[] array2)
{
  if (array1.Length != array2.Length)
  {
    return false;
  }

  for (int i = 0; i < array1.Length; i++)
  {
    if (array1[i] != array2[i])
    {
      return false;
    }
  }

  return true;
}

비밀번호마다 항상 새 소금을 사용하십시오. 소금은 비밀로 유지 될 필요가 없으며 해시 자체와 함께 저장 될 수 있습니다.


3
이 조언에 감사드립니다-시작하는 데 정말로 도움이되었습니다. 나는 또한이 링크를 발견했다 < dijksterhuis.org/creating-salted-hash-values-in-c >이 글에서 좋은 실질적인 조언과 많은 내용을 발견했다
Alex P

18
CompareByteArrays에 대한 멋진 LINQ 문 리 팩터 return array1.Length == array2.Length && !array1.Where((t, i) => t != array2[i]).Any();
헌터

6
@Brettski 기술적으로는 그렇습니다. 그러나 각 사용자마다 고유 한 소금을 사용하면 Rainbow Tables (일반적으로 해시 된 암호를 해독하는 가장 효율적인 방법으로 받아 들여짐)가 사실상 쓸모 없게됩니다. 이것은 암호를 안전하게 저장하는 방법과 왜 / 어떻게 작동하는지에 대한 심층적 인 개요를 제공합니다.
레인저

3
@hunter : 일정 시간을 유지하려면 .ToList ()를 추가해야합니다. 예 : return array1.Length == array2.Length &&! array1.Where ((t, i) => t! = array2 [i]). ToList (). Any (); 그렇지 않으면 LINQ는 같지 않은 1 바이트를 찾으면 즉시 반환됩니다.
Alex Rouillard

17
빠른 해시 함수를 사용하는 경우 -1입니다. PBKDF2, bcrypt 또는 scrypt와 같은 느린 구성을 사용하십시오.
코드 InChaos

48

blowdart가 말한 것은 있지만 코드가 약간 적습니다. Linq를 사용하거나 CopyTo배열을 연결 하십시오 .

public static byte[] Hash(string value, byte[] salt)
{
    return Hash(Encoding.UTF8.GetBytes(value), salt);
}

public static byte[] Hash(byte[] value, byte[] salt)
{
    byte[] saltedValue = value.Concat(salt).ToArray();
    // Alternatively use CopyTo.
    //var saltedValue = new byte[value.Length + salt.Length];
    //value.CopyTo(saltedValue, 0);
    //salt.CopyTo(saltedValue, value.Length);

    return new SHA256Managed().ComputeHash(saltedValue);
}

Linq는 바이트 배열을 쉽게 비교할 수있는 방법을 제공합니다.

public bool ConfirmPassword(string password)
{
    byte[] passwordHash = Hash(password, _passwordSalt);

    return _passwordHash.SequenceEqual(passwordHash);
}

그러나이 중 하나를 구현하기 전에이 게시물을 확인하십시오. . 비밀번호 해싱의 경우 빠른 알고리즘이 아닌 느린 해시 알고리즘을 원할 수 있습니다.

이를 위해 Rfc2898DeriveBytes느리고 (느려질 수있는) 클래스가 있으며, 비밀번호와 소금을 가져와 해시를 반환 할 수 있다는 점에서 원래 질문의 두 번째 부분에 대답 할 수 있습니다. 자세한 내용은 이 질문 을 참조하십시오. 참고 스택 교환 사용Rfc2898DeriveBytes (소스 코드를 암호 해시를 위해 여기 ).


6
@MushinNoShin SHA256은 빠른 해시입니다. 비밀번호 해싱에는 PBKDF2, bcrypt 또는 scrypt와 같은 느린 해시가 필요합니다. 비밀번호를 안전하게 해시하는 방법을 참조하십시오 . 자세한 내용은 security.se에서 확인하십시오.
코드 InChaos

32

SHA256과 같은 해싱 함수는 실제로 암호 저장에 사용하기위한 것이 아니라는 것을 읽었습니다. https://patrickmn.com/security/storing-passwords-securely/#notpasswordhashes

대신 PBKDF2, bcrypt 또는 scrypt와 같은 적응 형 키 파생 함수가있었습니다. 다음은 Microsoft가 Microsoft.AspNet.Identity 라이브러리에서 PasswordHasher 에 대해 작성한 PBKDF2 기반 제품입니다 .

/* =======================
 * HASHED PASSWORD FORMATS
 * =======================
 * 
 * Version 3:
 * PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
 * Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
 * (All UInt32s are stored big-endian.)
 */

public string HashPassword(string password)
{
    var prf = KeyDerivationPrf.HMACSHA256;
    var rng = RandomNumberGenerator.Create();
    const int iterCount = 10000;
    const int saltSize = 128 / 8;
    const int numBytesRequested = 256 / 8;

    // Produce a version 3 (see comment above) text hash.
    var salt = new byte[saltSize];
    rng.GetBytes(salt);
    var subkey = KeyDerivation.Pbkdf2(password, salt, prf, iterCount, numBytesRequested);

    var outputBytes = new byte[13 + salt.Length + subkey.Length];
    outputBytes[0] = 0x01; // format marker
    WriteNetworkByteOrder(outputBytes, 1, (uint)prf);
    WriteNetworkByteOrder(outputBytes, 5, iterCount);
    WriteNetworkByteOrder(outputBytes, 9, saltSize);
    Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length);
    Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length);
    return Convert.ToBase64String(outputBytes);
}

public bool VerifyHashedPassword(string hashedPassword, string providedPassword)
{
    var decodedHashedPassword = Convert.FromBase64String(hashedPassword);

    // Wrong version
    if (decodedHashedPassword[0] != 0x01)
        return false;

    // Read header information
    var prf = (KeyDerivationPrf)ReadNetworkByteOrder(decodedHashedPassword, 1);
    var iterCount = (int)ReadNetworkByteOrder(decodedHashedPassword, 5);
    var saltLength = (int)ReadNetworkByteOrder(decodedHashedPassword, 9);

    // Read the salt: must be >= 128 bits
    if (saltLength < 128 / 8)
    {
        return false;
    }
    var salt = new byte[saltLength];
    Buffer.BlockCopy(decodedHashedPassword, 13, salt, 0, salt.Length);

    // Read the subkey (the rest of the payload): must be >= 128 bits
    var subkeyLength = decodedHashedPassword.Length - 13 - salt.Length;
    if (subkeyLength < 128 / 8)
    {
        return false;
    }
    var expectedSubkey = new byte[subkeyLength];
    Buffer.BlockCopy(decodedHashedPassword, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length);

    // Hash the incoming password and verify it
    var actualSubkey = KeyDerivation.Pbkdf2(providedPassword, salt, prf, iterCount, subkeyLength);
    return actualSubkey.SequenceEqual(expectedSubkey);
}

private static void WriteNetworkByteOrder(byte[] buffer, int offset, uint value)
{
    buffer[offset + 0] = (byte)(value >> 24);
    buffer[offset + 1] = (byte)(value >> 16);
    buffer[offset + 2] = (byte)(value >> 8);
    buffer[offset + 3] = (byte)(value >> 0);
}

private static uint ReadNetworkByteOrder(byte[] buffer, int offset)
{
    return ((uint)(buffer[offset + 0]) << 24)
        | ((uint)(buffer[offset + 1]) << 16)
        | ((uint)(buffer[offset + 2]) << 8)
        | ((uint)(buffer[offset + 3]));
}

.NET Standard 2.0 (.NET 4.6.1 이상) 이 필요한 Microsoft.AspNetCore.Cryptography.KeyDerivation nuget 패키지가 설치되어 있어야합니다. 이전 버전의 .NET은 암호화를 참조하십시오. Microsoft의 System.Web.Helpers 라이브러리에서 클래스를 .

2015 년 11 월
업데이트 PBKDF2-HMAC-SHA1 대신 PBKDF2-HMAC-SHA256 해싱을 사용하는 다른 Microsoft 라이브러리의 구현을 사용하도록 업데이트되었습니다 ( IterCount가 충분히 높은 경우 PBKDF2-HMAC-SHA1은 여전히 안전 합니다). 단순화 된 코드가 복사 된 소스를 확인할 수 있습니다. 이전 답변에서 구현 된 해시의 유효성 검사 및 업그레이드를 실제로 처리하므로 나중에 iterCount를 늘려야하는 경우 유용합니다.


1
PBKDF2IterCount를 더 높은 숫자로 늘리는 것이 좋습니다 . 자세한 내용은 security.stackexchange.com/q/3959 를 참조하십시오 .
Michael

2
1) PBKDF2SubkeyLength20 바이트로 줄 입니다. 이것이 자연스러운 크기 f SHA1이며 그 이상으로 늘리면 공격자의 속도를 늦추지 않으면 서 수비수가 느려집니다. 2) 반복 횟수를 늘리는 것이 좋습니다. 실적 예산에 따라 10k에서 100k를 권장합니다. 3) 일정한 시간 비교는 아프지 않지만 실질적인 영향은 크지 않습니다.
코드 InChaos

KeyDerivationPrf, KeyDerivation 및 BlockCopy가 정의되지 않았습니다. 클래스는 무엇입니까?
mrbengi

@mrbengi 언급 한 Microsoft.AspNet.Cryptography.KeyDerivation 너겟 패키지를 설치 했습니까? 그 적합하지 있다면 여기 nuget 패키지를 필요로하지 않는 버전입니다. Buffer.BlockCopy는 시스템의 일부 여야합니다.
Michael

1
너겟 패키지는 이제 Microsoft.AspNetCore.Cryptography.KeyDerivation입니다.
제임스 블레이크

25

Salt는 해시에 복잡성을 추가하여 무차별 대입 균열을 어렵게 만듭니다.

Sitepoint기사에서 :

해커는 여전히 사전 공격을 수행 할 수 있습니다. 예를 들어, 악의적 인 사용자는 사람들이 자주 사용하는 암호 (예 : 도시 이름, 스포츠 팀 등)를 100,000 개 암호를 사용하여 해시 한 다음 사전의 각 항목을 데이터베이스의 각 행과 비교하여 사전 공격을 수행 할 수 있습니다. 표. 해커가 일치하면 빙고! 그들은 당신의 암호를 가지고 있습니다. 그러나이 문제를 해결하려면 해시에만 소금을 바르십시오.

해시를 소금에 담기 위해 무작위로 보이는 텍스트 문자열을 만들어 사용자가 제공 한 암호로 연결 한 다음 무작위로 생성 된 문자열과 암호를 하나의 값으로 함께 해시합니다. 그런 다음 해시와 솔트를 모두 Users 테이블에 별도의 필드로 저장합니다.

이 시나리오에서 해커는 암호를 추측해야 할뿐만 아니라 소금도 추측해야합니다. 일반 텍스트에 솔트를 추가하면 보안이 향상됩니다. 이제 해커가 사전 공격을 시도하면 모든 사용자 행의 솔트로 100,000 개의 항목을 해시해야합니다. 여전히 가능하지만 해킹 성공 가능성은 급격히 감소합니다.

.NET에는 자동 으로이 작업을 수행하는 방법이 없으므로 위의 솔루션을 사용하십시오.


소금은 무지개 테이블과 같은 것들을 방어하는 데 사용됩니다. 사전 공격에 대비하기 위해서는 KDF와 같은 작업 요소 (키 스트레칭이라고도 함)가 필요합니다. en.wikipedia.org/wiki/Key_stretching
Erwan Legrand

11

다음과 같은 방법으로 클래스를 만들었습니다.

  1. 소금 만들기
  2. 해시 입력
  3. 입력 확인

    public class CryptographyProcessor
    {
        public string CreateSalt(int size)
        {
            //Generate a cryptographic random number.
              RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
             byte[] buff = new byte[size];
             rng.GetBytes(buff);
             return Convert.ToBase64String(buff);
        }
    
    
          public string GenerateHash(string input, string salt)
          { 
             byte[] bytes = Encoding.UTF8.GetBytes(input + salt);
             SHA256Managed sHA256ManagedString = new SHA256Managed();
             byte[] hash = sHA256ManagedString.ComputeHash(bytes);
             return Convert.ToBase64String(hash);
          }
    
          public bool AreEqual(string plainTextInput, string hashedInput, string salt)
          {
               string newHashedPin = GenerateHash(plainTextInput, salt);
               return newHashedPin.Equals(hashedInput); 
          }
     }

    `



3

Microsoft에서 제공하는 기본 클래스를 사용하여 해싱 프로세스를 쉽게 수행 할 수 있도록 라이브러리 SimpleHashing.Net 을 만들었습니다. 일반 SHA로는 더 이상 암호를 안전하게 저장하기에 충분하지 않습니다.

라이브러리는 Bcrypt의 해시 형식이라는 아이디어를 사용하지만 공식 MS 구현이 없기 때문에 프레임 워크 (예 : PBKDF2)에서 사용할 수있는 것을 사용하는 것을 선호하지만 상자에서 너무 어렵습니다.

다음은 라이브러리 사용 방법에 대한 간단한 예입니다.

ISimpleHash simpleHash = new SimpleHash();

// Creating a user hash, hashedPassword can be stored in a database
// hashedPassword contains the number of iterations and salt inside it similar to bcrypt format
string hashedPassword = simpleHash.Compute("Password123");

// Validating user's password by first loading it from database by username
string storedHash = _repository.GetUserPasswordHash(username);
isPasswordValid = simpleHash.Verify("Password123", storedHash);

2

이것이 내가하는 방법입니다. 해시를 만들고 ProtectedDataAPI를 사용하여 저장합니다 .

    public static string GenerateKeyHash(string Password)
    {
        if (string.IsNullOrEmpty(Password)) return null;
        if (Password.Length < 1) return null;

        byte[] salt = new byte[20];
        byte[] key = new byte[20];
        byte[] ret = new byte[40];

        try
        {
            using (RNGCryptoServiceProvider randomBytes = new RNGCryptoServiceProvider())
            {
                randomBytes.GetBytes(salt);

                using (var hashBytes = new Rfc2898DeriveBytes(Password, salt, 10000))
                {
                    key = hashBytes.GetBytes(20);
                    Buffer.BlockCopy(salt, 0, ret, 0, 20);
                    Buffer.BlockCopy(key, 0, ret, 20, 20);
                }
            }
            // returns salt/key pair
            return Convert.ToBase64String(ret);
        }
        finally
        {
            if (salt != null)
                Array.Clear(salt, 0, salt.Length);
            if (key != null)
                Array.Clear(key, 0, key.Length);
            if (ret != null)
                Array.Clear(ret, 0, ret.Length);
        } 
    }

    public static bool ComparePasswords(string PasswordHash, string Password)
    {
        if (string.IsNullOrEmpty(PasswordHash) || string.IsNullOrEmpty(Password)) return false;
        if (PasswordHash.Length < 40 || Password.Length < 1) return false;

        byte[] salt = new byte[20];
        byte[] key = new byte[20];
        byte[] hash = Convert.FromBase64String(PasswordHash);

        try
        {
            Buffer.BlockCopy(hash, 0, salt, 0, 20);
            Buffer.BlockCopy(hash, 20, key, 0, 20);

            using (var hashBytes = new Rfc2898DeriveBytes(Password, salt, 10000))
            {
                byte[] newKey = hashBytes.GetBytes(20);

                if (newKey != null)
                    if (newKey.SequenceEqual(key))
                        return true;
            }
            return false;
        }
        finally
        {
            if (salt != null)
                Array.Clear(salt, 0, salt.Length);
            if (key != null)
                Array.Clear(key, 0, key.Length);
            if (hash != null)
                Array.Clear(hash, 0, hash.Length);
        }
    }

    public static byte[] DecryptData(string Data, byte[] Salt)
    {
        if (string.IsNullOrEmpty(Data)) return null;

        byte[] btData = Convert.FromBase64String(Data);

        try
        {
            return ProtectedData.Unprotect(btData, Salt, DataProtectionScope.CurrentUser);
        }
        finally
        {
            if (btData != null)
                Array.Clear(btData, 0, btData.Length);
        }
    }

    public static string EncryptData(byte[] Data, byte[] Salt)
    {
        if (Data == null) return null;
        if (Data.Length < 1) return null;

        byte[] buffer = new byte[Data.Length];

        try
        {
            Buffer.BlockCopy(Data, 0, buffer, 0, Data.Length);
            return System.Convert.ToBase64String(ProtectedData.Protect(buffer, Salt, DataProtectionScope.CurrentUser));
        }
        finally
        {
            if (buffer != null)
                Array.Clear(buffer, 0, buffer.Length);
        }
    }

저장하는 동안과 나중에 비교할 때 어떻게 호출합니까?
SearchForKnowledge

2

모든 답변을 읽었 으며 느리게 해싱하는 @Michael 기사와 @CodesInChaos에 대한 좋은 의견은 충분하다고 생각 하지만 해싱 / 유효성 검사에 유용한 코드 스 니펫을 공유하기로 결정했으며 [ Microsoft.AspNet.Cryptography .KeyDerivation ].

    private static bool SlowEquals(byte[] a, byte[] b)
            {
                uint diff = (uint)a.Length ^ (uint)b.Length;
                for (int i = 0; i < a.Length && i < b.Length; i++)
                    diff |= (uint)(a[i] ^ b[i]);
                return diff == 0;
            }

    private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
            {
                Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt);
                pbkdf2.IterationCount = iterations;
                return pbkdf2.GetBytes(outputBytes);
            }

    private static string CreateHash(string value, int salt_bytes, int hash_bytes, int pbkdf2_iterations)
            {
                // Generate a random salt
                RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
                byte[] salt = new byte[salt_bytes];
                csprng.GetBytes(salt);

                // Hash the value and encode the parameters
                byte[] hash = PBKDF2(value, salt, pbkdf2_iterations, hash_bytes);

                //You need to return the salt value too for the validation process
                return Convert.ToBase64String(hash) + ":" + 
                       Convert.ToBase64String(hash);
            }

    private static bool ValidateHash(string pureVal, string saltVal, string hashVal, int pbkdf2_iterations)
            {
                try
                {
                    byte[] salt = Convert.FromBase64String(saltVal);
                    byte[] hash = Convert.FromBase64String(hashVal);

                    byte[] testHash = PBKDF2(pureVal, salt, pbkdf2_iterations, hash.Length);
                    return SlowEquals(hash, testHash);
                }
                catch (Exception ex)
                {
                    return false;
                }
            }

매우 중요한 SlowEquals 기능에주의를 기울이십시오. 마지막으로,이 도움이 되었으면 좋겠습니다.


사용 중 루프를 만드는 대신 인공적인 비 사용 지연을 설정하십시오. 예를 들어 Task.Delay 사용. 이렇게하면 무차별 대입 시도가 지연되지만 활성 스레드는 차단되지 않습니다.
gburton

@gburton 조언 해 주셔서 감사합니다. 나는 그것을 점검 할것이다.
QMaster

CreateHash에는 오타가 있습니다. 소금 대신 Convert.ToBase64String (hash)을 자체로 연결합니다. 그 외에도, 이것은 다른 답변에 대한 의견에서 제기 된 거의 모든 문제를 다루는 좋은 답변입니다.
ZeRemz

2

System.Web.Helpers.CryptoMicrosoft 의 NuGet 패키지를 사용하십시오 . 해시에 솔트를 자동으로 추가합니다.

다음과 같이 비밀번호를 해시하십시오. var hash = Crypto.HashPassword("foo");

다음과 같은 비밀번호를 확인하십시오. var verified = Crypto.VerifyHashedPassword(hash, "foo");


1

asp.net 또는 .net 코어를 사용하지 않으면> = .Net Standard 2.0 프로젝트에서도 쉬운 방법이 있습니다.

먼저 해시 생성 기간과 관련된 해시, 솔트 및 반복 수의 원하는 크기를 설정할 수 있습니다.

private const int SaltSize = 32;
private const int HashSize = 32;
private const int IterationCount = 10000;

비밀번호 해시와 솔트를 생성하려면 다음과 같이 사용할 수 있습니다.

public static string GeneratePasswordHash(string password, out string salt)
{
    using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, SaltSize))
    {
        rfc2898DeriveBytes.IterationCount = IterationCount;
        byte[] hashData = rfc2898DeriveBytes.GetBytes(HashSize);
        byte[] saltData = rfc2898DeriveBytes.Salt;
        salt = Convert.ToBase64String(saltData);
        return Convert.ToBase64String(hashData);
    }
}

사용자가 입력 한 비밀번호가 유효한지 확인하려면 데이터베이스의 값을 확인하십시오.

public static bool VerifyPassword(string password, string passwordHash, string salt)
{
    using (Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(password, SaltSize))
    {
        rfc2898DeriveBytes.IterationCount = IterationCount;
        rfc2898DeriveBytes.Salt = Convert.FromBase64String(salt);
        byte[] hashData = rfc2898DeriveBytes.GetBytes(HashSize);
        return Convert.ToBase64String(hashData) == passwordHash;
    }
}

다음 단위 테스트는 사용법을 보여줍니다.

string password = "MySecret";

string passwordHash = PasswordHasher.GeneratePasswordHash(password, out string salt);

Assert.True(PasswordHasher.VerifyPassword(password, passwordHash, salt));
Assert.False(PasswordHasher.VerifyPassword(password.ToUpper(), passwordHash, salt));

Microsoft Rfc2898DeriveBytes 소스


-1

원래 질문 "비밀번호 해시를위한 다른 C # 방법이 있습니까?"의이 부분에 대한 대답으로 ASP.NET Identity v3.0 https://www.nuget.org/packages/Microsoft.AspNet.Identity를 사용하여이 작업을 수행 할 수 있습니다 . EntityFramework / 3.0.0-rc1- 최종

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using System.Security.Principal;

namespace HashTest{


    class Program
    {
        static void Main(string[] args)
        {

            WindowsIdentity wi = WindowsIdentity.GetCurrent();

            var ph = new PasswordHasher<WindowsIdentity>();

            Console.WriteLine(ph.HashPassword(wi,"test"));

            Console.WriteLine(ph.VerifyHashedPassword(wi,"AQAAAAEAACcQAAAAEA5S5X7dmbx/NzTk6ixCX+bi8zbKqBUjBhID3Dg1teh+TRZMkAy3CZC5yIfbLqwk2A==","test"));

        }
    }


}

-1
 protected void m_GenerateSHA256_Button1_Click(objectSender, EventArgs e)
{
string salt =createSalt(10);
string hashedPassword=GenerateSHA256Hash(m_UserInput_TextBox.Text,Salt);
m_SaltHash_TextBox.Text=Salt;
 m_SaltSHA256Hash_TextBox.Text=hashedPassword;

}
 public string createSalt(int size)
{
 var rng= new System.Security.Cyptography.RNGCyptoServiceProvider();
 var buff= new byte[size];
rng.GetBytes(buff);
 return Convert.ToBase64String(buff);
}


 public string GenerateSHA256Hash(string input,string salt)
{
 byte[]bytes=System.Text.Encoding.UTF8.GetBytes(input+salt);
 new System.Security.Cyptography.SHA256Managed();
 byte[]hash=sha256hashString.ComputedHash(bytes);
 return bytesArrayToHexString(hash);
  }

다른 방법은 string password = HashPasswordForStoringInConfigFile (TextBox1.Text, SHA1)입니다
ankush shukla

-6
create proc [dbo].[hash_pass] @family nvarchar(50), @username nvarchar(50), @pass nvarchar(Max),``` @semat nvarchar(50), @tell nvarchar(50)

as insert into tbl_karbar values (@family,@username,(select HASHBYTES('SHA1' ,@pass)),@semat,@tell)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.