string pass = FormsAuthentication.HashPasswordForStoringInConfigFile(password, "SHA1");
I use above function to make SH1 string password.So how i can do opposite of that.How I can make SH1 String to password.Please reply soon.
This is not possible. When you hash data with SHA1 (or MD5 or whatever) you lose information, the original string can't be recovered.
The only sensible thing you can do with a hash is to compare it with the result of hashing of another string to determine if the entered password is correct:
bool passwordMaches = (pass ==
FormsAuthentication.HashPasswordForStoringInConfigFile(enteredPassword, "SHA1"));
Related
Before we begin I want to make it clear that I know how bad this question is. It's a terrible situation but I'm being constrained by some very strange specifications.
I know that not only should you not try to write your own wrappers for this kind of stuff, but Microsoft have made it clear this shouldn't even be used. So before you start writing replies saying "Why are you even doing this" please try to understand that I have had these conversations with my superiors already, but the push for new features and lack of time means that despite it being atrocious; nevertheless - here I am.
We have an ASP Net membership database, started some time well before my time at this company and now hosting some 40k users. We have a platform in .Net 3.5 which lets users log in.
My job currently is to write an API in .Net Core 2.1 part of which is to allow for user creation and updating but there in lies the problem - migrating from Membership to Identity is not an option so I've been told to create a wrapper for the stored procedures in the Membership database.
This has been mostly successful with the only issue being; the subject of this question. Creating a user via aspnet_Membership_CreateUser I need to submit the data in such a way that it can be successfully validated in our platform.
I had originally followed this post but found that it's been designed for PasswordFormat 1 - Hashed; I then found that our user base used PasswordFormat 2 - Encrypted and as such the users I was creating would not validate.
The code looked something like this
public bool CreateUser(string userName, string password, string email, string securityQuestion, string securityAnswer, bool isApproved)
{
bool success = false;
//Just so I can attempt to login afterwards
password = "Hello World!";
//Our password and password salt need to be base64 encoded before we can save them to the DB
string salt = Guid.NewGuid().ToString();
string encryptedSalt = salt.Base64Encode();
//Concatenate our salt and password
IEnumerable<byte> saltedpass = salt.GetBytes(Encoding.UTF8).Concat(password.GetBytes(Encoding.UTF8));
//Use SHA1 to hash more - equivilant to the HASHBYTES('SHA1' T-SQL
byte[] sha1HashedPass = PasswordHelper.HashBytes(_validationMethod, saltedpass.ToArray(), _validationKey);
string hashedPass = sha1HashedPass.ToBase64String();
int errorCode = MembershipCreateUser(_applicationName, userName, hashedPass, encryptedSalt, email, securityQuestion, securityAnswer, isApproved);
if (errorCode == 0)
{
success = true;
}
return success;
}
Worth noting that _validationKey is the machine key shared across the applications which use this database, which I'm passing into the SHA1 mechanism.
So, intentionally and woefully bad security practice aside;
Is there a way in C# to generate an encrypted (not hashed) passwords and salts in this way?
Thank you for the comments - thankfully we were able to support Hashed passwords in our platform; the issue was with my code and not ASP Membership.
As mentioned I was taking a post that was originally written in T-SQL and trying to build a C# implementation of it. My implementation of this code was incorrect and as such the passwords and salts I was generating were not able to be validated by ASP Net Membership, this was not obvious in my original post because I had obfuscated the method which was SHA1 hashing my data.
//Using hard coded just for example
string username = "joeborder";
string password = "Hello World!";
string salt = "TastySalt";
Encoding encoder = Encoding.Unicode; //Encoding was also incorrect
//Our password and password salt need to be base64 encoded before we can save them to the DB
string encryptedSalt = salt.Base64Encode();
//Concatenate our salt and password
IEnumerable<byte> saltedpass = salt.GetBytes(encoder).Concat(password.GetBytes(encoder));
//Use SHA1 to hash more - equivilant to the HASHBYTES('SHA1') T-SQL
var SHA1Hasher = new SHA1CryptoServiceProvider(); //Originally I was using HMACSHA1 which was producing a different output
byte[] sha1HashedPass = SHA1Hasher.ComputerHash(saltedpass.ToArray());
string hashedPass = sha1HashedPass.ToBase64String();
/*
EXEC aspnet_Membership_CreateUser
#ApplicationName = "MyApp",
#UserName = username,
#Password = hashedPass,
#PasswordSalt = encryptedSalt,
...Etc
*/
Then in our .Net 3.5 application the following code would work
string username = "joeborder";
string password = "Hello World!";
if (Membership.ValidateUser(username, password))
{
Console.WriteLine("You've gotta be kidding me thats a clutch");
}
I have created a wesite in asp.net and use ms-sql database to save the records. Now want to convert it in node.js application. And want to use same sql database. In asp.net application I have encrypt the password for registered user. Below is code.
public static string CreateHash(string unHashed)
{
System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
byte[] data = System.Text.Encoding.ASCII.GetBytes(unHashed);
data = x.ComputeHash(data);
return System.Text.Encoding.ASCII.GetString(data);
}
public static bool MatchHash(string HashData, string HashUser)
{
HashUser = CreateHash(HashUser);
if (HashUser == HashData)
return true;
else
return false;
}
Now problem is that how I use same encryption in node.js. So when node application is ready old user can also make login. It only possible if node app also use same encryption that I have use in asp.net.
For node I have created all environment and use mssql module for database communication. Please help me fix that. Thanks!!
First of all MD5 shall no longer be used if you are serious about security.
Based on your comment and code, I fear there is a 'data loss' in the initial ASP.net code.
Let us have a look at CreateHash function again, I've added comments:
public static string CreateHash(string unHashed)
{
System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
// Convert unHashed string to bytes using ASCII coding
byte[] data = System.Text.Encoding.ASCII.GetBytes(unHashed);
// Compute MD5 hash from bytes
data = x.ComputeHash(data);
// Decode MD5 resulting bytes as ASCII
return System.Text.Encoding.ASCII.GetString(data);
}
The last line confuses me, it is decoding bytes received from MD5 function as if they were ASCII, but that is incorrect assumption. And the resulting encoded string as you gave in comment contains lots of "?'s".
Next node.js code will do similar except encode the string using hex rather than ascii:
var crypto = require('crypto')
function createHash(data) {
return crypto.createHash('md5').update(data, 'ascii').digest('hex')
}
To emulate "bytes to ascii" you could try .digest('binary') instead of hex. If it does not give what you expect, then you have to make a separate 'conversion' step from hex to ascii. (I am not experienced enough to give you elegant solution to the later one)
I'm trying to migrate to the new Universal Membership providers (from a home brew solution). I've migrated our old User table to the Users/Memberships table.
When I run Membership.ValidateUser(txtUsername.Text.Trim(), txtPassword.Text.Trim()), it always returns false, even though I know the username/password is correct.
Here is how I generated the password, hash, and salt:
var salt = Crypto.GenerateSalt();
var hashedPassword = this.GenerateHashWithSalt(password, salt);
This is the GenerateHashWithSalt method I'm using
private string GenerateHashWithSalt(string password, string salt)
{
string hashWithSalt = password + salt;
byte[] saltedHashBytes = Encoding.UTF8.GetBytes(hashWithSalt);
HashAlgorithm algo = HashAlgorithm.Create(Membership.HashAlgorithmType);
byte[] hash = algo.ComputeHash(saltedHashBytes);
return Convert.ToBase64String(hash);
}
I've also gone with:
var salt = Crypto.GenerateSalt();
var saltedPassword = password + salt;
var hashedPassword = Crypto.HashPassword(saltedPassword);
Neither of these seem to work. What am I missing?
Scott
Bah, answered it.
So step 1 of all of this was migrating users from our 2-way encrypted passwords to 1 way hash.
Every example I saw of doing that included hashing the password manually. Turns out Membership.CreateUser(username,password); hashes the password (and salts), so I was hashing a hashed password, which is why auth was failing.
I simply had to call Membership.CreateUser, passing in the username & plain text pass, and it worked. Weee!
I have to send a username and password from my iphone app to a ASP server page, and I will encrypt them using: http://iphonedevelopment.blogspot.com/2009/02/strong-encryption-for-cocoa-cocoa-touch.html. What is the best way to decrypt these strings on the ASP page? I found some examples, but since the encryption will happen on two completely unrelated sides, I think I need to hard code the key in on both sides, and I can't find any examples that don't have use generated keys.
Thanks!
Yes, key management is a big problem. You will have to have the keys on both sides, on iOS you can save the key in the Keychain, that is secure but the process to get it there securely is more difficult.
The other main issue is getting all the parameters the same on both sides. Of particular interest are
encryption key value and size
mode: CBC, ECB, etc. (you should probably be using CBC)
initialization vector (iv) is needed for most modes
padding method: PKCS7, etc. (AES is a block cypher and needs input
in a multiple of block size)
Why not store the passwords in the database with SHA1, then use HMAC with a client specified key for the communication?
Have the server generate a random key and send it with the login request. The client computes the SHA1 hash of the password, then computes the HMAC SHA1 hash of that using the server-specified key. The server then verifies that the result is correct.
On the client end:
// password is the plaintext password
// keyb64 is a random key specified by the server, encoded in base64.
string ComputeSecureHash(string password, string keyb64)
{
byte[] data = Encoding.UTF8.GetBytes(password);
byte[] key = Convert.FromBase64String(keyb64);
byte[] hash;
byte[] machash;
// compute a plain SHA1 hash of the specified data
using (SHA1Managed sha1 = new SHA1Managed())
{
hash = sha1.ComputeHash(data);
}
// now compute a HMAC hash of that hash, using the random key.
using (HMACSHA1 sha1mac = new HMACSHA1(key))
{
machash = sha1mac.ComputeHash(hash);
}
return Convert.ToBase64String(machash);
}
On the server end:
// hash is the string produced by the function above
// realHash is the SHA1 hash of the real password, which you've fetched from the db
// key is the key you generated for this login session
bool VerifyHash(string hash, byte[] realHash, byte[] key)
{
byte[] machash;
using (HMACSHA1 sha1mac = new HMACSHA1(key))
{
machash = sha1mac.ComputeHash(realHash);
}
return (Convert.ToBase64String(machash) == hash);
}
This allows you to authenticate over a plaintext medium without having the password cracked.
Is this how hashed password stored in SQL Server should look like?
alt text http://img28.imageshack.us/img28/2545/88871034.gif
This is function I use to hash password (I found it in some tutorial)
public string EncryptPassword(string password)
{
//we use codepage 1252 because that is what sql server uses
byte[] pwdBytes = Encoding.GetEncoding(1252).GetBytes(password);
byte[] hashBytes = System.Security.Cryptography.MD5.Create().ComputeHash(pwdBytes);
return Encoding.GetEncoding(1252).GetString(hashBytes);
}
EDIT
I tried to use sha-1 and now strings seem to look like as they are suppose to:
public string EncryptPassword(string password)
{
return FormsAuthentication.HashPasswordForStoringInConfigFile(password, "sha1");
}
// example output: 39A43BDB7827112409EFED3473F804E9E01DB4A8
Result from the image above looks like broken string, but this sha-1 looks normal....
Will this be secure enough?
Your're close, but not quite there.
For a secure hash, you will need a salt value in another column. Second, try to stay away from MD5 as a hashing provider. It's not as secure as SHA-1 or SHA-2. SHA-1 is included in .NET just like MD5 is.