decrypt md5 hash confusion [duplicate] - c#

This question already has answers here:
Is it possible to decrypt MD5 hashes?
(24 answers)
Closed 1 year ago.
I have develop a simple MD5 hash like this:
public static string Hash(string value)
{
byte[] valueBytes = new byte[value.Length * 2];
Encoder encoder = Encoding.Unicode.GetEncoder();
encoder.GetBytes(value.ToCharArray(), 0, value.Length, valueBytes, 0, true);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes("123456"));
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
stringBuilder.Append(hashBytes[i].ToString("x2"));
}
return stringBuilder.ToString();
}
But now, I want to decrypt the result of this code to original text. But I don't know which function I should use?
My hash function is:
byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes("123456"));

You don't (can't) decrypt a hash, you perform the encrypt again against a given value to validate that this value is the same as the one the hash pretends to belong to.

Related

Comparing hashed password with salt always fails

I saw multiple questions about password hashing and salt but they all seem to fail for me. I use this function to hash/salt it and then put it to database:
public string HashPassword(string password)
{
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
var pbkdf2 = new Rfc2898DeriveBytes(PasswordTextbox.Password, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);
byte[] hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);
string savedPasswordHash = Convert.ToBase64String(hashBytes);
return savedPasswordHash;
}
and then I try to compare it with user input using this function:
public static void UnhashPassword(string hashedPassword, string hashedPasswordFromDatabase)
{
byte[] hashBytes = Convert.FromBase64String(hashedPasswordFromDatabase);
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
var pbkdf2 = new Rfc2898DeriveBytes(hashedPassword, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);
for (int i = 0; i < 20; i++)
if (hashBytes[i + 16] != hash[i])
throw new UnauthorizedAccessException();
}
the second function always throws exception. Not sure what is the reason since this answer seemed to work for everybody in other question.
Without a good Minimal, Complete, and Verifiable code example that reliably reproduces the problem, it's impossible to say for sure what is wrong. However, the following code example does work exactly as expected (i.e. the value of result is true after it's been initialized by the call to ValidatePassword():
static void Main(string[] args)
{
string password = "password";
string hashedPassword = HashPassword(password);
bool result = ValidatePassword(password, hashedPassword);
}
static string HashPassword(string password)
{
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);
byte[] hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);
string savedPasswordHash = Convert.ToBase64String(hashBytes);
return savedPasswordHash;
}
static bool ValidatePassword(string password, string hashedPasswordFromDatabase)
{
byte[] hashBytes = Convert.FromBase64String(hashedPasswordFromDatabase);
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);
for (int i = 0; i < 20; i++)
{
if (hashBytes[i + 16] != hash[i])
{
return false;
}
}
return true;
}
The only material change between the above and your original code is that the HashPassword() method uses the password value passed in, rather than PasswordTextbox.Password.
Based on that observation, I can only surmise that in your own scenario, you are not really hashing the same password as you are validating later. Whether this is because PasswordTextbox.Password never did have the right password, or you are passing a different password later, I can't say.
If the above code example does not adequately point you in the right direction so that you can get your code working, please improve your question so that it includes a good MCVE.

Ruby sha and hash to c#

Im trying to translate this to c#
f1 = Digest::SHA1.hexdigest(#password)
f2 = nonce + ":" + f1
Digest::MD5.hexdigest(f2)
My Code
private static string GetSHA1HashData(string data)
{
//create new instance of md5
SHA1 sha1 = SHA1.Create();
//convert the input text to array of bytes
byte[] hashData = sha1.ComputeHash(Encoding.Default.GetBytes(data));
//create new instance of StringBuilder to save hashed data
StringBuilder returnValue = new StringBuilder();
//loop for each byte and add it to StringBuilder
for (int i = 0; i < hashData.Length; i++)
{
returnValue.Append(hashData[i].ToString());
}
// return hexadecimal string
return returnValue.ToString();
}
public static string CreateMD5Hash(string input)
{
// Use input string to calculate MD5 hash
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
// Convert the byte array to hexadecimal string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
// To force the hex string to lower-case letters instead of
// upper-case, use he following line instead:
// sb.Append(hashBytes[i].ToString("x2"));
}
return sb.ToString();
}
Call
var nonce = "1386755695841";
var password = "edc123";
var sha = GetSHA1HashData(password);
var md5 = CreateMD5Hash(nonce + ":" + sha);
But i cant get it right, any ideas
The problem is that .NET uses UTF-16 by default whilst Ruby will use something else (normally UTF-8, but it may also respect encoding that has been set by database or web source).
I think you just need to alter one line:
//convert the input text to array of bytes
byte[] hashData = sha1.ComputeHash(Encoding.ASCII.GetBytes(data));
You may need UTF-8 or even some other encoding instead, depending on the range of passwords accepted by the Ruby version. However, the ASCII coding should at least prove correctness of this answer in general from your sample data.

How to make a password protected file in C#

I know this question has been asked before but the answer simply wasn't what I needed. I need to create a password protected text file. I don't mean to encrypt but just create a file with a simple text password. It would also be nice to find out how to open this file in C# as well.
Create a plain-text password protected file and open this file at a later time. All in C#.
Password protecting a text file that is not encrypted is not really possible. However, you can validate if your text file has been modified, so that you are aware it has been altered by someone.
The concept is simple. Use a password to encrypt or obfuscate a hash of the data (text file). You can the later check this hash against the current data and determine whether or not it matches. You will need to store this signature (encrypted hash) somewhere maybe in a file called (textfile.sig).
You can use the SHA1Managed .NET class to create the hash, and the TripleDESCryptoServiceProvider class to encrypt the resulting hash.
something like...
public string GetSignature(string text, string password)
{
byte[] key;
byte[] key2;
GetKeys(password, out key, out key2);
string sig = encryptstring(GetSHA1(text), key, key2);
}
public void GetKeys(string password, out byte[] key, out byte[] key2)
{
byte[] data = StringToByte(password);
SHA1 sha = new SHA1CryptoServiceProvider();
MD5 md5 = new MD5CryptoServiceProvider();
byte[] hash1 = sha.ComputeHash(data);
byte[] hash2 = md5.ComputeHash(data);
// Generate some key data based on the supplied password;
byte[] key = new byte[24];
for (int i = 0; i < 20; i++)
{
key[i] = hash1[i];
}
for (int i = 0; i < 4; i++)
{
key[i + 20] = hash2[i];
}
byte[] key2 = new byte[8];
for (int i = 0; i < 8; i++)
{
key2[i] = hash2[i+4];
}
}
public string GetSHA1(string text)
{
UnicodeEncoding UE = new UnicodeEncoding();
byte[] hashValue;
byte[] message = UE.GetBytes(text);
SHA1Managed hashString = new SHA1Managed();
string hex = "";
hashValue = hashString.ComputeHash(message);
foreach (byte x in hashValue)
{
hex += String.Format("{0:x2}", x);
}
return hex;
}
public string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
public string encryptstring(string instr, byte[] key, byte[] key2)
{
TripleDES threedes = new TripleDESCryptoServiceProvider();
threedes.Key = key;
threedes.IV = key2;
ICryptoTransform encryptor = threedes.CreateEncryptor(key, key2);
MemoryStream msEncrypt = new MemoryStream();
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
// Write all data to the crypto stream and flush it.
csEncrypt.Write(StringToByte(instr), 0, StringToByte(instr).Length);
csEncrypt.FlushFinalBlock();
return ByteToString(msEncrypt.ToArray());
}
public string decryptstring(string instr, byte[] key, byte[] key2)
{
if (string.IsNullOrEmpty(instr)) return "";
TripleDES threedes = new TripleDESCryptoServiceProvider();
threedes.Key = key;
threedes.IV = key2;
ICryptoTransform decryptor = threedes.CreateDecryptor(key, key2);
// Now decrypt the previously encrypted message using the decryptor
MemoryStream msDecrypt = new MemoryStream(HexStringToByte(instr));
CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
try
{
return ByteToString(csDecrypt);
}
catch (CryptographicException)
{
return "";
}
}
Otherwise, you will if you want to hide the data from people, you need to encrypt the data in the text file. You can do this by calling encryptstring() with the full text data instead of the hash of the data.
Whole point of the question was to not have to encrypt the data manually but let Windows deal with it so I decided to go with Hans Passant's suggestion and simply use a password protected zip file with the needed information (txt files) inside it. This can be easily done with DotNetZip.

Manually Converting Password and Salt to Compare with ASPNETDB Password

I'm trying to manually compare the aspnetdb password field with a manually-hashed password on my end to check for validity (I can't use the default Membership implementation as I'm using a custom one). Anyway, I'm taking the Base64 password salt from the record, and using the following algorithm to get the salted hash:
static byte[] GenerateSaltedHash(byte[] plainText, byte[] salt)
{
HashAlgorithm algorithm = new SHA256Managed();
byte[] plainTextWithSaltBytes =
new byte[plainText.Length + salt.Length];
for (int i = 0; i < plainText.Length; i++)
{
plainTextWithSaltBytes[i] = plainText[i];
}
for (int i = 0; i < salt.Length; i++)
{
plainTextWithSaltBytes[plainText.Length + i] = salt[i];
}
byte[] hash = algorithm.ComputeHash(plainTextWithSaltBytes);
return hash;
}
I then take those bytes and compare with a Convert.GetBase64Bytes(MembershipUser.Password). There's a disconnect somewhere though as the bytes I get from the Convert method and my computed hash are never the same even when I know the passwords are the same.
Any insight on where I'm going wrong?
In looking at the source for SqlMembershipProvider, it appears that they copy the salt before the password:
static byte[] GenerateSaltedHash(byte[] plainText, byte[] salt)
{
HashAlgorithm algorithm = new SHA256Managed();
byte[] plainTextWithSaltBytes = new byte[plainText.Length + salt.Length];
salt.CopyTo(plainTextWithSaltBytes, 0);
plainText.CopyTo(plainTextWithSaltBytes, salt.Length);
byte[] hash = algorithm.ComputeHash(plainTextWithSaltBytes);
return hash;
}

How do I use the OpenSSL.Net C# wrapper to encrypt a string with AES?

I am trying to send some encrypted data from my SharePoint site to my company's PeopleSoft site. The PeopleSoft folks insist that I have to use the OpenSSL library for my encryption. I have downloaded and installed the OpenSSL.Net project from SourceForge.
For my purposes, I need to simply encrypt a string with AES. I know how to do this with the System.Security.Cryptography library, but am having a very difficult time translating this to the OpenSSL.Net side. Very frustrating, since I can see everything that I think I need in Intellisense!
Does anybody have an example of performing string encryption/decryption with AES using the OpenSSL.Net wrapper?
Thanks!
-Nick
Here is the sample which works for me. I simplified it by using copy-paste but should not matter.
I'm using text password due to compatibility with JS library but open SSL itself supports direct usage of byte[] Key and IV so it's up to you what to use.
In order to switch binary data into the string just use
Encoding.UTF8.GetBytes() and Encoding.UTF8.GetString()
to convert back and forth.
public Byte[] Encrypt(Byte[] data, String password)
{
//Just random 8 bytes for salt
var salt = new Byte[] {1, 2, 3, 4, 5, 6, 7, 8};
using (var cc = new CipherContext(Cipher.AES_256_CBC))
{
//Constructing key and init vector from string password
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] iv;
byte[] key = cc.BytesToKey(MessageDigest.MD5, salt, passwordBytes, 1, out iv);
var memoryStream = new MemoryStream();
//Performing encryption thru unmanaged wrapper
var aesData = cc.Crypt(data, key, iv, true);
//Append salt so final data will look Salted___SALT|RESTOFTHEDATA
memoryStream.Write(Encoding.UTF8.GetBytes("Salted__"), 0, 8);
memoryStream.Write(salt, 0, 8);
memoryStream.Write(aesData, 0, aesData.Length);
return memoryStream.ToArray();
}
}
public Byte[] Decrypt(String password, Byte[] encryptedData)
{
byte[] salt = null;
//extracting salt if presented
if (encryptedData.Length > 16)
{
if (Encoding.UTF8.GetString(encryptedData).StartsWith("Salted__"))
{
salt = new Byte[8];
Buffer.BlockCopy(encryptedData, 8, salt, 0, 8);
}
}
//Removing salt from the original array
int aesDataLength = encryptedData.Length - 16;
byte[] aesData = new byte[aesDataLength];
Buffer.BlockCopy(encryptedData, 16, aesData, 0, aesDataLength);
using (var cc = new CipherContext(Cipher.AES_256_CBC))
{
//Constructing key and init vector from string password and salt
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] iv;
byte[] key = cc.BytesToKey(MessageDigest.MD5, salt, passwordBytes, 1, out iv);
//Decrypting
return cc.Decrypt(aesData, key, iv, 0);
}
}

Categories