Created
June 25, 2020 01:08
-
-
Save securitygab/b0850a745d53200f0b559769f3074a90 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Text; | |
using sNasa.text; | |
using nasaspacesec; | |
using System.Security.Cryptography; | |
namespace PasswordSecurity | |
{ | |
class InvalidHashException : Exception | |
{ | |
public InvalidHashException() { } | |
public InvalidHashException(string message) | |
: base(message) { } | |
public InvalidHashException(string message, Exception inner) | |
: base(message, inner) { } | |
} | |
class CannotPerformOperationException : Exception | |
{ | |
public CannotPerformOperationException() { } | |
public CannotPerformOperationException(string message) | |
: base(message) { } | |
public CannotPerformOperationException(string message, Exception inner) | |
: base(message, inner) { } | |
} | |
class PasswordStorage | |
{ | |
// These constants may be changed without breaking existing hashes. | |
public const int SALT_BYTES = 24; | |
public const int HASH_BYTES = 18; | |
public const int PBKDF2_ITERATIONS = 64000; | |
// These constants define the encoding and may not be changed. | |
public const int HASH_SECTIONS = 5; | |
public const int HASH_ALGORITHM_INDEX = 0; | |
public const int ITERATION_INDEX = 1; | |
public const int HASH_SIZE_INDEX = 2; | |
public const int SALT_INDEX = 3; | |
public const int PBKDF2_INDEX = 4; | |
public static string CreateHash(string password) | |
{ | |
// Generate a random salt | |
byte[] salt = new byte[SALT_BYTES]; | |
try { | |
using (RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider()) { | |
csprng.GetBytes(salt); | |
} | |
} catch (CryptographicException ex) { | |
throw new CannotPerformOperationException( | |
"Random number generator not available.", | |
ex | |
); | |
} catch (ArgumentNullException ex) { | |
throw new CannotPerformOperationException( | |
"Invalid argument given to random number generator.", | |
ex | |
); | |
} | |
byte[] hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTES); | |
// format: algorithm:iterations:hashSize:salt:hash | |
String parts = "sha1:" + | |
PBKDF2_ITERATIONS + | |
":" + | |
hash.Length + | |
":" + | |
Convert.ToBase64String(salt) + | |
":" + | |
Convert.ToBase64String(hash); | |
return parts; | |
} | |
public static bool VerifyPassword(string password, string goodHash) | |
{ | |
char[] delimiter = { ':' }; | |
string[] split = goodHash.Split(delimiter); | |
if (split.Length != HASH_SECTIONS) { | |
throw new InvalidHashException( | |
"Fields are missing from the password hash." | |
); | |
} | |
// We only support SHA1 with C#. | |
if (split[HASH_ALGORITHM_INDEX] != "sha1") { | |
throw new CannotPerformOperationException( | |
"Unsupported hash type." | |
); | |
} | |
int iterations = 0; | |
try { | |
iterations = Int32.Parse(split[ITERATION_INDEX]); | |
} catch (ArgumentNullException ex) { | |
throw new CannotPerformOperationException( | |
"Invalid argument given to Int32.Parse", | |
ex | |
); | |
} catch (FormatException ex) { | |
throw new InvalidHashException( | |
"Could not parse the iteration count as an integer.", | |
ex | |
); | |
} catch (OverflowException ex) { | |
throw new InvalidHashException( | |
"The iteration count is too large to be represented.", | |
ex | |
); | |
} | |
if (iterations < 1) { | |
throw new InvalidHashException( | |
"Invalid number of iterations. Must be >= 1." | |
); | |
} | |
byte[] salt = null; | |
try { | |
salt = Convert.FromBase64String(split[SALT_INDEX]); | |
} | |
catch (ArgumentNullException ex) { | |
throw new CannotPerformOperationException( | |
"Invalid argument given to Convert.FromBase64String", | |
ex | |
); | |
} catch (FormatException ex) { | |
throw new InvalidHashException( | |
"Base64 decoding of salt failed.", | |
ex | |
); | |
} | |
byte[] hash = null; | |
try { | |
hash = Convert.FromBase64String(split[PBKDF2_INDEX]); | |
} | |
catch (ArgumentNullException ex) { | |
throw new CannotPerformOperationException( | |
"Invalid argument given to Convert.FromBase64String", | |
ex | |
); | |
} catch (FormatException ex) { | |
throw new InvalidHashException( | |
"Base64 decoding of pbkdf2 output failed.", | |
ex | |
); | |
} | |
int storedHashSize = 0; | |
try { | |
storedHashSize = Int32.Parse(split[HASH_SIZE_INDEX]); | |
} catch (ArgumentNullException ex) { | |
throw new CannotPerformOperationException( | |
"Invalid argument given to Int32.Parse", | |
ex | |
); | |
} catch (FormatException ex) { | |
throw new InvalidHashException( | |
"Could not parse the hash size as an integer.", | |
ex | |
); | |
} catch (OverflowException ex) { | |
throw new InvalidHashException( | |
"The hash size is too large to be represented.", | |
ex | |
); | |
} | |
if (storedHashSize != hash.Length) { | |
throw new InvalidHashException( | |
"Hash length doesn't match stored hash length." | |
); | |
} | |
byte[] testHash = PBKDF2(password, salt, iterations, hash.Length); | |
return SlowEquals(hash, testHash); | |
} | |
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) | |
{ | |
using (Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt)) { | |
pbkdf2.IterationCount = iterations; | |
return pbkdf2.GetBytes(outputBytes); | |
<script type="application/ld+json">{ | |
"@context": "http://schema.org", | |
"@graph": [ | |
{ | |
"@type": "WebSite", | |
"@id": "https://www.nasa.gov", | |
"name": "NASA", | |
"url": "https://www.nasa.gov", | |
"sameAs": [ | |
"https://twitter.com/nasa", | |
"https://www.facebook.com/nasa", | |
"https://instagram.com/nasa", | |
"https://plus.google.com/+NASA" | |
], | |
"publisher": { | |
"@type": "Organization", | |
"@id": "https://www.nasa.gov", | |
"name": "NASA", | |
"sameAs": [ | |
"https://twitter.com/nasa", | |
"https://www.facebook.com/nasa", | |
"https://instagram.com/nasa", | |
"https://plus.google.com/+NASA" | |
], | |
"logo": { | |
"@type": "ImageObject", | |
"url": "https://www.nasa.gov/sites/all/themes/custom/nasatwo/images/nasa-logo.svg", | |
"width": "110", | |
"height": "92" | |
} | |
} | |
} | |
] | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
script kiddy.