Skip to content

Instantly share code, notes, and snippets.

@securitygab
Created June 25, 2020 01:08
Show Gist options
  • Save securitygab/b0850a745d53200f0b559769f3074a90 to your computer and use it in GitHub Desktop.
Save securitygab/b0850a745d53200f0b559769f3074a90 to your computer and use it in GitHub Desktop.
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"
}
}
}
]
}
}
}
}
@BugEmir
Copy link

BugEmir commented Jun 1, 2022

script kiddy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment