Decrypt SHA1 value with C# - c#

I have a PHP web service that I've discovered is passing my C# a SHA-1 encrupted value. The sample data that is passed to me is "8cb2237d0679ca88db6464eac60da96345513964" which I know translates to "12345".
How do I translate the hashed value back to "12345" with code similar to the following
public static string HashCode(string str)
{
string rethash = "";
try
{
System.Security.Cryptography.SHA1 hash = System.Security.Cryptography.SHA1.Create();
System.Text.ASCIIEncoding encoder = new System.Text.ASCIIEncoding();
byte[] combined = encoder.GetBytes(str);
hash.ComputeHash(combined);
rethash = Convert.ToBase64String(hash.Hash);
}
catch (Exception ex)
{
string strerr = "Error in HashCode : " + ex.Message;
}
return rethash;
}
EDIT *
Here is some RUBY code that is also workig with "8cb2237d0679ca88db6464eac60da96345513964" and "12345"
require "digest/sha1"
class User
attr_accessor :password
def initialize(password)
#password = hash_password(password)
end
def hash_password(password)
Digest::SHA1.hexdigest(password)
end
def valid_password?(password)
#password == hash_password(password)
end
end
u = User.new("12345")
p u.password # => "8cb2237d0679ca88db6464eac60da96345513964"
p u.valid_password?("not valid") # => false
p u.valid_password?("12345") # => true

You can't decrypt SHA1 hash because it's a one way hash.
Another example of one way hashing is MD5

The ruby code that you posted doesn't appear to be reversing a hash.
What it seems to be doing is this:
Get the password text, hash it and store it.
Later, when it wants to check that the "user" entered the same password again, it gets the password text from the user, hashes it, and compares the hash value to the stored hash value.
This is a common way to store and check passwords. Instead of "dehashing" the stored value for comparison, you hash the new value and compare the two hash values.

12345 will always come out as 8cb2237d0679ca88db6464eac60da96345513964 with a straight hash.
This means that if you made a database of every possible result, you could in theory look up the result and from that see what the original input to the sha1 function was.
This is a security problem, with issues like Dictionary Attacks and Rainbow tables being possible (http://en.wikipedia.org/wiki/Rainbow_table).
To get around that, you should never use an unsalted hash. i.e. you always customise your hash using a value known to you.
For example sha1("12345" + "mySalt").
Now your hash is easy for you to work out, but not the same as every other person in the world who has used sha1.
Technically speaking, you should also never reuse the same salt twice either, but that is a more complicated concept.
EDIT: As owlstead points out below, PBKDF2 and a random salt should be used, rather than a static one and a hash. Far better for security.

The code you are looking for is this
SHA1 sha = new SHA1CryptoServiceProvider();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] combined = encoder.GetBytes(pin);
string hash = BitConverter.ToString(sha.ComputeHash(combined)).Replace("-", "");
Where pin is the unhashed value, and hash is the value you want compaired

Hashing is not a reversible operation, like encryption.

Hashing is not encryption. Hashing is one way, and is used in most cases to verify data integrity.

Related

What would be the best way to implement SHA512 into my code?

So I need to store passwords in a SQL database and it would be insecure to store them in plain text. For a variety of reasons, I chose SHA512 to hash the passwords prior to storage. I, for the life of me, can not identify how to take data from a Secure string gained from user input, and hash it using SHA512 (which also means I haven't been able to look into salting it either).
I have seen online that you call a new instance of SHA512 but that it has to be managed (?) but when I try it shows that it is obsolete. Looking further, the wise internet suggested the create method of SHA512... which is also obsolete.
Any help into how I can hash and salt a secure string would be great.
Here is a basic hash and salt method using SHA512 and a random salt prepended to the hash.
private static string HashAndSalt(string plaintext)
{
var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
using var hasher = SHA512.Create();
var random = new Random();
var ciphertextBytes = hasher.ComputeHash(Encoding.UTF8.GetBytes(plaintext));
var ciphertextB64 = Convert.ToBase64String(ciphertextBytes);
var salt = new string(Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray());
var ciphertext = salt + ':' + ciphertextB64;
return ciphertext;
}
You will need to convert your SecureString to a normal string. Using a SecureString is obsolete and should not be used anymore. As the comments mentioned you should look into a dedicated password hashing algorithm such as:
PBKDF2
Argon2
Bcrypt
Scrypt
Here is an example using Bcrypt - it is not too complicated.
First, grab this NuGet package: BCrypt.Net-Next
private static string BcryptHash(string plaintext)
{
var ciphertext = BCrypt.Net.BCrypt.HashPassword(plaintext, 12);
return ciphertext;
}
You can't however compare the hashes when a user tries to authenticate as you can with SHA512. You need to use Bcrypts 'Verify' function.
private static bool BcryptVerify(string plaintext)
{
return BCrypt.Net.BCrypt.Verify(plaintext, hashedPassword);
}
Where the plaintext is the plaintext password you receive from user input and the hashedPassword being the hash you retrieved from the database where the initial ciphertext was stored.
Hope this helps.
I think this is what you are asking?
public static string GetHash(string s)
{
using var h = SHA512.Create();
return Convert.ToBase64String(h.ComputeHash(Encoding.UTF8.GetBytes(s)));
}
Have a look here for some other inspirations of how to do this:
https://github.com/aspnet/AspNetWebStack/blob/main/src/System.Web.Helpers/Crypto.cs

How to validate salted and hashed password with C#

I have the following problem that I've been dealing for a couple of hours by now and it's driving nuts.
Context
I have a legacy database that stored passwords using the following algorithm. The legacy code used a Python library.
PBKDF2 with SHA256
1000 iterations
Salt has a length of 8
Password is stored like this $salt$hashedPassword
I'm switching login flow for the new system and I need to migrate that old algorithm to a new one. New system uses .netcore
Question
What I'm trying to do is even possible?. How can I achieve it?
What my logic dictates is that I can take the salt and recreate the hashing algorithm using .netcore Crypto library but its not working and the function returns always false.
Legacy Code
from werkzeug.security import generate_password_hash, check_password_hash
def setPassword(self, password):
self.password = generate_password_hash(password, method='pbkdf2:sha256')
Where generate_password_hash comes from the library, this is the code
SALT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
def generate_password_hash(password, method="pbkdf2:sha256", salt_length=8):
"""Hash a password with the given method and salt with a string of
the given length. The format of the string returned includes the method
that was used so that :func:`check_password_hash` can check the hash.
The format for the hashed string looks like this::
method$salt$hash
This method can **not** generate unsalted passwords but it is possible
to set param method='plain' in order to enforce plaintext passwords.
If a salt is used, hmac is used internally to salt the password.
If PBKDF2 is wanted it can be enabled by setting the method to
``pbkdf2:method:iterations`` where iterations is optional::
pbkdf2:sha256:80000$salt$hash
pbkdf2:sha256$salt$hash
:param password: the password to hash.
:param method: the hash method to use (one that hashlib supports). Can
optionally be in the format ``pbkdf2:<method>[:iterations]``
to enable PBKDF2.
:param salt_length: the length of the salt in letters.
"""
salt = gen_salt(salt_length) if method != "plain" else ""
h, actual_method = _hash_internal(method, salt, password)
return "%s$%s$%s" % (actual_method, salt, h)
def gen_salt(length):
"""Generate a random string of SALT_CHARS with specified ``length``."""
if length <= 0:
raise ValueError("Salt length must be positive")
return "".join(_sys_rng.choice(SALT_CHARS) for _ in range_type(length))
Code
using System;
using System.Security.Cryptography;
using System.Text;
namespace test_pwd
{
class Program
{
static void Main(string[] args)
{
var res = SameHash("Qwerty12", "84e8c8a5dbdafaf23523ffa5dfecf29d53522a35ca4c76fa877c5fcf9eb4b654", "laSgSC6R");
Console.WriteLine(res);
}
public static bool SameHash(string userpwd, string storedHash, string storedSalt)
{
var saltByte = Encoding.UTF8.GetBytes(storedSalt);
var rfc = new Rfc2898DeriveBytes(userpwd, saltByte, 1000);
var baseString = Convert.ToBase64String(rfc.GetBytes(64));
return baseString == storedHash;
}
}
}
Base string is converted into
k6vhCweBNz8ymMeEdhi+1czrea+oTTYLrW1OuwdinA78AFyEXKitpKUGLCt1ZdyS1Vka8Cptzd5u5Uzdbi4MbA==
Which is not the same as the stored password hash I'm sending. What I'm doing wrong or this idea is even feasible?.

Convert C# to Ruby - HMAC SHA256 function

I'm trying to get the HMAC SHA256 value(str_signature), I followed the Ruby code from this post, although his example was converting code from Java(with a Hex key).
C#
string strRawSignature = "200123123891:12|11231231|GET|just%20test%20value"
// Convert signature to byte array in order to compute the hash
byte[] bSignature = Encoding.UTF8.GetBytes(strRawSignature);
// Convert ApiKey to byte array - for initializing HMACSHA256
byte[] bSecretKey = Convert.FromBase64String(strApiKey);
string strSignature = "";
using (HMACSHA256 hmac = new HMACSHA256(bSecretKey))
{
// Compute signature hash
byte[] bSignatureHash = hmac.ComputeHash(bSignature);
// Convert signature hash to Base64String for transmission
str_signature = Convert.ToBase64String(bSignatureHash);
}
Ruby
require "openssl"
require "base64"
digest = OpenSSL::Digest.new('sha256')
key = [ 'xiIm9FuYhetyijXA2QL58TRlvhuSJ73FtdxiSNU2uHE=' ]
#this is just a dummy signature to show what the possible values are
signature = "200123123891:12|11231231|GET|just%20test%20value"
hmac = OpenSSL::HMAC.digest(digest, key.pack("m*"), signature)
str_signature = Base64.urlsafe_encode64(hmac)
example result: "B0NgX1hhW-rsnadD2_FF-grcw9pWghwMWgG47mU4J94="
Update:
Changed the pack method to output base64 strings.
Edited variable names for concistency
References:
Used hexdigest, has a different ouput string length.
This example uses the digest method, although I'm not sure what value the key parameter has, hopefully it's a base 64 encoded string.
This uses hexdigest again. I am pretty sure that digest is the method to go vs hexdigest, since hexdigest ouput has a longer string compared to the sample HMAC value I have from C# script.
Finally got the monkey of my back!
I don't really need to create a sha256 digest object after all, I just had to put the 'sha256' parameter.
require 'openssl'
require "base64"
#API_KEY = base64 encoded string
key = Base64.decode64(API_KEY)
hash = OpenSSL::HMAC.digest('sha256', key, "Message")
puts Base64.encode64(hash)
thanks to this link

C#: comparing the password hash with the user input different sizes , when Authenticating the user

I have made a user registration where I have salted the user password and hashed it using SHA256.
later, when the user needs to log into my system I need to have his password salted and hashed, so I :
1.retrieved the salt "string" from Database
2. converted the salt into bytes
3. created a new byte[] = [inputPassword.length + salt.length]
4. and hashed that.
now the new hash is shorter than Original hash ...(using same hashing functions)
given these information what do you think the problem might be ...
is storing the salt as CHAR on my database wrong , if yes what or how should I save it ?
Note: both hashes are compared on byte level.
Note: all user information are stored in the database password and salt as CHAR
thank you in advance
You could generate a salt from a Guid converted into a base 64 string, then save that in the database as char. I use nvarchar to maximise my options using a .NET string.
Then you can implement something like this for generating the original password hash, and comparing the hash when the user logs in:
public static byte[] GetHash(string password, string salt)
{
byte[] unhashedBytes = Encoding.Unicode.GetBytes(String.Concat(salt, password));
SHA256Managed sha256 = new SHA256Managed();
byte[] hashedBytes = sha256.ComputeHash(unhashedBytes);
return hashedBytes;
}
public static bool CompareHash(string attemptedPassword, byte[] hash, string salt)
{
string base64Hash = Convert.ToBase64String(hash);
string base64AttemptedHash = Convert.ToBase64String(GetHash(attemptedPassword, salt));
return base64Hash == base64AttemptedHash;
}
Usually hash functions return fixed size hash, so if you tell that new hash is shorter I think problem might be in your hash function.

Best way to store hashed passwords and salt values in the database - varchar or binary?

Once I've generated a salt and hashed the password (using bcrypt, etc) would it be best to store the results as a string or as a byte array in the database? Are there any benefits either way? Or is it a more subjective decision?
If you use VARCHAR either make sure the bytes are either valid characters or force the bytes to ASCII before you save the hash and salt. To make is safer from data corruption you may want to either encode the bytes in Base64 or Hexadecimal before you store them in the VARCHAR field.
For example, if you store the byte[] output from MD5 or SHA1 some of the byte values may be removed or replaced when the byte[] is converted to text is they are not valid UTF-8/Unicode. This should not be as much of a problem if you are using ASCII but it could still cause data corruption.
If you don't want to deal with Hex you could use this base64 method Convert.ToBase64String that is built into the framework.
If you use VARBINARY and don't try to use and text encoding methods this issue should not exist, but could make comparing hashes more difficult.
...Note that if you use NVARCHAR this data corruption could still occur...
static void Main(string[] args)
{
var salt = "MySalt";
var password = "MyPassword";
var saltedKey = CalculateHash(salt, password);
Console.WriteLine(saltedKey);
// MySalt$teGOpFi57nENIRifSW3m1RQndiU=
var checkHash = CheckHash(saltedKey, password);
Console.WriteLine(checkHash);
// True
}
private static string CalculateHash(string saltOrSaltedKey, string password)
{
var salt =
saltOrSaltedKey.Contains('$')
? saltOrSaltedKey.Substring(0, saltOrSaltedKey.IndexOf('$') + 1)
: saltOrSaltedKey + '$';
var newKey = Encoding.UTF8.GetBytes(salt + password);
var sha1 = SHA1.Create();
sha1.Initialize();
var result = sha1.ComputeHash(newKey);
// if you replace this base64 version with one of the encoding
// classes this will become corrupt due to nulls and other
// control character values in the byte[]
var outval = salt + Convert.ToBase64String(result);
return outval;
}
private static bool CheckHash(string saltedKey, string password)
{
var outval = CalculateHash(saltedKey, password);
return outval == saltedKey;
}
VARCHAR should be sufficient. In my opinion VARCHAR data will be easier to consume and work with vs. binary.
The built in ASP.NET membership providers also store hashed passwords as VARCHAR fields.
most md5/sha1 libraries return hashes base64 encoded in which case varchar would suffice

Categories