[C#/ASP.NET MVC/.NET6] KeyDerivation 클래스 : Pbkdf2 정적 메소드를 사용해 패스워드 해시값 구하기
C#/ASP.NET MVC 2022. 9. 7. 00:05728x90
반응형
728x170
■ KeyDerivation 클래스의 Pbkdf2 정적 메소드를 사용해 패스워드 해시값을 구하는 방법을 보여준다.
▶ Program.cs
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
namespace TestProject;
/// <summary>
/// 프로그램
/// </summary>
class Program
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 네트워크 바이트 순서 쓰기 - WriteNetworkByteOrder(targetByteArray, offset, value)
/// <summary>
/// 네트워크 바이트 순서 쓰기
/// </summary>
/// <param name="targetByteArray">타겟 바이트 배열</param>
/// <param name="offset">오프셋</param>
/// <param name="value">32비트 부호없는 정수</param>
private static void WriteNetworkByteOrder(byte[] targetByteArray, int offset, uint value)
{
targetByteArray[offset + 0] = (byte)(value >> 24);
targetByteArray[offset + 1] = (byte)(value >> 16);
targetByteArray[offset + 2] = (byte)(value >> 8 );
targetByteArray[offset + 3] = (byte)(value >> 0 );
}
#endregion
#region 네트워크 바이트 순서 읽기 - ReadNetworkByteOrder(sourceByteArray, offset)
/// <summary>
/// 네트워크 바이트 순서 읽기
/// </summary>
/// <param name="sourceByteArray">소스 바이트 배열</param>
/// <param name="offset">오프셋</param>
/// <returns>32비트 부호없는 정수</returns>
private static uint ReadNetworkByteOrder(byte[] sourceByteArray, int offset)
{
return ((uint)(sourceByteArray[offset + 0]) << 24) |
((uint)(sourceByteArray[offset + 1]) << 16) |
((uint)(sourceByteArray[offset + 2]) << 8 ) |
((uint)(sourceByteArray[offset + 3]));
}
#endregion
#region 패스워드 해시 계산하기 - CalculatePasswordHash(password)
/// <summary>
/// 패스워드 해시 계산하기
/// </summary>
/// <param name="password">패스워드</param>
/// <returns>패스워드 해시</returns>
private static string CalculatePasswordHash(string password)
{
KeyDerivationPrf prf = KeyDerivationPrf.HMACSHA256;
RandomNumberGenerator generator = RandomNumberGenerator.Create();
const int iterationCount = 10000;
const int saltSize = 128 / 8;
const int byteCountRequested = 256 / 8;
byte[] saltByteArray = new byte[saltSize];
generator.GetBytes(saltByteArray);
byte[] subsidaryKeyByteArray = KeyDerivation.Pbkdf2(password, saltByteArray, prf, iterationCount, byteCountRequested);
byte[] targetByteArray = new byte[13 + saltByteArray.Length + subsidaryKeyByteArray.Length];
targetByteArray[0] = 0x01; // Format Marker
WriteNetworkByteOrder(targetByteArray, 1, (uint)prf );
WriteNetworkByteOrder(targetByteArray, 5, iterationCount);
WriteNetworkByteOrder(targetByteArray, 9, saltSize );
Buffer.BlockCopy(saltByteArray, 0, targetByteArray, 13, saltByteArray.Length);
Buffer.BlockCopy(subsidaryKeyByteArray, 0, targetByteArray, 13 + saltSize, subsidaryKeyByteArray.Length);
return Convert.ToBase64String(targetByteArray);
}
#endregion
#region 해시 검증하기 - VerifyHash(passwordHashed, password)
/// <summary>
/// 해시 검증하기
/// </summary>
/// <param name="passwordHashed">해시 패스워드</param>
/// <param name="password">패스워드</param>
/// <returns>해시 검증 결과</returns>
private static bool VerifyHash(string passwordHashed, string password)
{
byte[] passwordHashedByteArray = Convert.FromBase64String(passwordHashed);
if(passwordHashedByteArray[0] != 0x01)
{
return false;
}
KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(passwordHashedByteArray, 1);
int iterationCount = (int )ReadNetworkByteOrder(passwordHashedByteArray, 5);
int saltLength = (int )ReadNetworkByteOrder(passwordHashedByteArray, 9);
if(saltLength < 128 / 8)
{
return false;
}
byte[] saltByteArray = new byte[saltLength];
Buffer.BlockCopy(passwordHashedByteArray, 13, saltByteArray, 0, saltByteArray.Length);
int subsidaryKeyLength = passwordHashedByteArray.Length - 13 - saltByteArray.Length;
if(subsidaryKeyLength < 128 / 8)
{
return false;
}
byte[] expectedSubsidaryKeyByteArray = new byte[subsidaryKeyLength];
Buffer.BlockCopy(passwordHashedByteArray, 13 + saltByteArray.Length, expectedSubsidaryKeyByteArray, 0, expectedSubsidaryKeyByteArray.Length);
byte[] actualSubsidaryKeyByteArray = KeyDerivation.Pbkdf2(password, saltByteArray, prf, iterationCount, subsidaryKeyLength);
return actualSubsidaryKeyByteArray.SequenceEqual(expectedSubsidaryKeyByteArray);
}
#endregion
#region 프로그램 시작하기 - Main()
/// <summary>
/// 프로그램 시작하기
/// </summary>
private static void Main()
{
string password = "test1234";
string passwordHashed = CalculatePasswordHash(password);
Console.WriteLine($"패스워드 : {password}");
Console.WriteLine($"해시 패시워드 : {passwordHashed}");
Console.WriteLine($"검증 결과 : {VerifyHash(passwordHashed, password)}");
}
#endregion
}
728x90
반응형
그리드형(광고전용)
댓글을 달아 주세요