Reversing a string hash function - c#

I have the following function that hashes a string:
public static uint hashString(string myString)
{
uint hash = 0;
foreach (char c in myString)
{
hash *= 0x1F;
hash += c;
}
return hash;
}
So if I want to hash hello it will produce 99162322.
Is it possible to write a reverse function that takes in a number and spits out the string (given that the string result is unknown)?

Since you don't use cryptographic hash, your implementation is easy to reverse (i.e. return some string which has the given hash value)
Code:
public static uint hashString(string myString) {
//DONE: validate public methods' parameters
if (null == myString)
return 0;
uint hash = 0;
//DONE: hash function must never throw exceptions
unchecked {
foreach (char c in myString) {
hash *= 0x1F;
hash += c;
}
}
return hash;
}
private static string HashReverse(uint value) {
StringBuilder sb = new StringBuilder();
for (; value > 0; value /= 31)
sb.Append((char)(value % 31));
return string.Concat(sb.ToString().Reverse());
}
Demo: (given a hash we produce a string and compute hash from it to check)
uint[] tests = new uint[] {
99162322,
123,
456
};
// Since the string can contain control characters, let's provide its Dump
string Dump(string value) => string.Join(" ", value.Select(c =>((int) c).ToString("x4")));
string report = string.Join(Environment.NewLine, tests
.Select(test => new {
test,
reversed = HashReverse(test)
})
.Select(item => $"{item.test,9} :: {Dump(item.reversed),-30} :: {hashString(item.reversed),9}"));
Console.WriteLine(report);
Outcome:
99162322 :: 0003 000e 000b 0012 0012 0012 :: 99162322
123 :: 0003 001e :: 123
456 :: 000e 0016 :: 456
Please, note, that many a string produce the same hash value (say, "hello" and mine "\u0003\u000e\u000b\u0012\u0012\u0012")

No.
One of the fundamental points of hashing is that it's irreversible.
There are many string that will produce the has 99162322, so while it might be possible to find all of them (given a maximum string length), but there would be no way to determine which one was 'correct'.

Related

Include all printable characters in caesar cipher (ascii 32-126)

I'm looking to make a caesar cipher that includes common ASCII printable characters (character code 32-126).
My current code:
private static char Cipher(char ch, int key)
{
if (!char.IsLetter(ch))
return ch;
char offset = char.IsUpper(ch) ? 'A' : 'a';
return (char)((((ch + key) - offset) % 26) + offset);
}
public static string Encipher(string input, int key)
{
string output = string.Empty;
foreach (char ch in input)
output += Cipher(ch, key);
return output;
}
public static string Decipher(string input, int key) {return Encipher(input, 26 - key);}
(source: https://www.programmingalgorithms.com/algorithm/caesar-cipher/)
I assume I need to at least change
if (!char.IsLetter(ch)) *and* return Encipher(input, 26 - key);
to
if (char.IsControl(ch)) *and* return Encipher(input, 94 - key);
and change the modulo 26 to 94(?) but what else needs to be done? I assume the random number generator (this is for a one time pad implementation) needs to be changed as well, to 0-93 (or maybe 95??). However, testing this gave me errors and didn't make the output the same as the input. Maybe I need to make a isLetter check as well, so the isUpper check doesn't fail for non letters. What else am I missing?
private static char Cipher(char ch, int key)
{
if (char.IsControl(ch))
return ch;
char offset = ' ';
return (char)((((ch + key) - offset) % 95) + offset);
}
public static string Encipher(string input, int key)
{
string output = string.Empty;
foreach (char ch in input)
output += Cipher(ch, key);
return output;
}
public static string Decipher(string input, int key)
{
return Encipher(input, 95 - key);
}

How to XOR a MD5 hash and return a 32 character string?

How do I further encrypt a MD5 hash by XOR'ing it with a string of variable size (not bigger than 32 characters) ?
I would like the result of the XOR to be a 32 character string as well.
What i have tried so far is:
convert the md5 string to binary
convert second string to binary
pad second binary with 0's (to the left) until both binaries are of equal length
iterate the binary representations and XOR them
convert the XOR'ed result to a string
The approach may be wrong, im not sure how to do it. My problem is, when converting the result of the XOR, it is not a 32 character long string, as I would like it to be.
Sample code (equal length strings in this case):
class Program
{
static void Main(string[] args)
{
var md51 = ToBinary(ConvertToByteArray(CalculateMD5Hash("Maaa"), Encoding.ASCII));
var md52 = ToBinary(ConvertToByteArray(CalculateMD5Hash("Moo"), Encoding.ASCII));
List<int> xoredResult = new List<int>();
for (int i = 0; i < md51.Length; i++)
{
var string1 = md51[i];
var string2 = md52[i];
var xor = string1 ^ string2;
xoredResult.Add(xor);
}
var resultingString = string.Join("", xoredResult);
Console.WriteLine(resultingString.Length);
var data = GetBytesFromBinaryString(resultingString);
var text = Encoding.ASCII.GetString(data);
}
public static byte[] ConvertToByteArray(string str, Encoding encoding)
{
return encoding.GetBytes(str);
}
public static String ToBinary(Byte[] data)
{
return string.Join("", data.Select(byt => Convert.ToString(byt, 2).PadLeft(8, '0')));
}
public static Byte[] GetBytesFromBinaryString(String binary)
{
var list = new List<Byte>();
for (int i = 0; i < binary.Length; i += 8)
{
String t = binary.Substring(i, 8);
list.Add(Convert.ToByte(t, 2));
}
return list.ToArray();
}
public static string CalculateMD5Hash(string input)
{
// step 1, calculate MD5 hash from input
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hash = md5.ComputeHash(inputBytes);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
return sb.ToString();
}
}
xoring a string with what is essentially random bytes is not guaranteed to give you a valid string as a output. Your var text = Encoding.ASCII.GetString(data); is likely failing because you are passing it a non valid string in byte form. You must use something like var text = Convert.ToBase64String(data) to be able to represent the random data without loss of information in the process.

md5(wordpress) password encryption in c#

I want to authenticate user form asp.net web application. data base used for application is MySQL and password stored in db is in encrypted format which is generated from word press application. i need to encrypted password so that i can compare encrypted password with db password.
my password : Push#123
Encrypted password : $P$BGW0cKLlkN6VlZ7OqRUvIY1Uvo/Bh9/
How to generate this Encrypted password in c#
It took me a while, but here you have working almost 1:1 conversion from php to C#:
using System;
using System.Text;
using System.Security.Cryptography;
using System.Linq;
namespace WordpressHash {
public class Program {
private static string itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
public static void Main(string[]args) {
string StrPassword = "Push#123";
string expected = "$P$BGW0cKLlkN6VlZ7OqRUvIY1Uvo/Bh9/";
string computed = MD5Encode(StrPassword, expected);
Console.WriteLine(StrPassword);
Console.WriteLine(computed);
Console.WriteLine("Are equal? " + expected.Equals(computed));
}
static string MD5Encode(string password, string hash) {
string output = "*0";
if (hash == null) {
return output;
}
if (hash.StartsWith(output))
output = "*1";
string id = hash.Substring(0, 3);
// We use "$P$", phpBB3 uses "$H$" for the same thing
if (id != "$P$" && id != "$H$")
return output;
// get who many times will generate the hash
int count_log2 = itoa64.IndexOf(hash[3]);
if (count_log2 < 7 || count_log2 > 30)
return output;
int count = 1 << count_log2;
string salt = hash.Substring(4, 8);
if (salt.Length != 8)
return output;
byte[]hashBytes = {};
using(MD5 md5Hash = MD5.Create()) {
hashBytes = md5Hash.ComputeHash(Encoding.ASCII.GetBytes(salt + password));
byte[]passBytes = Encoding.ASCII.GetBytes(password);
do {
hashBytes = md5Hash.ComputeHash(hashBytes.Concat(passBytes).ToArray());
} while (--count > 0);
}
output = hash.Substring(0, 12);
string newHash = Encode64(hashBytes, 16);
return output + newHash;
}
static string Encode64(byte[]input, int count) {
StringBuilder sb = new StringBuilder();
int i = 0;
do {
int value = (int)input[i++];
sb.Append(itoa64[value & 0x3f]); // to uppercase
if (i < count)
value = value | ((int)input[i] << 8);
sb.Append(itoa64[(value >> 6) & 0x3f]);
if (i++ >= count)
break;
if (i < count)
value = value | ((int)input[i] << 16);
sb.Append(itoa64[(value >> 12) & 0x3f]);
if (i++ >= count)
break;
sb.Append(itoa64[(value >> 18) & 0x3f]);
} while (i < count);
return sb.ToString();
}
}
}
Every hash in the database is encoded using salt and n iterations of md5. Brief explanation can be found here: https://codex.wordpress.org/Function_Reference/wp_hash_password
Intentionally I have ommited salt generation. But if you will need it in the future, it should start with $P$ and be at least 12 characters long. Whit this extra method you will be able also to hash new passwords, not only check if hash is correct.
Probably this might do the trick for you
using System.Security.Cryptography;
class Program
{
static void Main(string[] args)
{
string StrPassword = "Push#123";
using (MD5 md5Hash = MD5.Create())
{
string hashPassword = GetMd5Hash(md5Hash, StrPassword);
Console.WriteLine(hashPassword);
}
}
static string GetMd5Hash(MD5 md5Hash, string input)
{
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
return sBuilder.ToString();
}
}
Hash functions map binary strings of an arbitrary length to small binary strings of a fixed length. A cryptographic hash function has the property that it is computationally infeasible to find two distinct inputs that hash to the same value; that is, hashes of two sets of data should match if the corresponding data also matches. Small changes to the data result in large, unpredictable changes in the hash.
The hash size for the MD5 algorithm is 128 bits.
The ComputeHash methods of the MD5 class return the hash as an array of 16 bytes. Note that some MD5 implementations produce a 32-character, hexadecimal-formatted hash. To interoperate with such implementations, format the return value of the ComputeHash methods as a hexadecimal value.
Source MSDN: MD5 Class
I've rewritten crypt_private php method from class-phpass.php (see /wp-includes/class-phpass.php of your wordpress installation) to use it in c#.
Password is user entered string, setting is user_pass value in wp database of wp_users row.
crypt_private return hash of password. So, if crypt_private returned value equals setting value, password is correct.
This works if you're using php5 and newer on server with wordpress.
private const string itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
public bool SignIn(string password)
{
string foundUserHash = "hash from database (saved password of a user)";
string hash = Crypt(password, foundUserHash);
return foundUserHash == hash;
}
private string Crypt(string password, string setting)
{
string output = "*0";
if (setting.Substring(0, 2) == output)
output = "*1";
string id = setting.Substring(0, 3);
if (id != "$P$" && id != "$H$")
return output;
int count_log2 = itoa64.IndexOf(setting[3]);
if (count_log2 < 7 || count_log2 > 30)
return output;
var count = 1 << count_log2;
string salt = setting.Substring(4, 8);
if (salt.Length != 8)
return output;
var hash = GetHash(
GetByteArraysAppended(
Encoding.UTF7.GetBytes(salt),
Encoding.UTF7.GetBytes(password)
));
do
{
hash = GetHash(
GetByteArraysAppended(
hash,
Encoding.UTF7.GetBytes(password)
));
}
while (--count!=0);
output = setting.Substring(0, 12);
output += encode64(hash, 16);
return output;
}
private string encode64(byte [] input, int count)
{
string output = "";
int i = 0;
do
{
Int32 value = input[i++];
output += itoa64[value & 0x3f];
if (i < count)
value |= input[i] << 8;
output += itoa64[(value >> 6) & 0x3f];
if (i++ >= count)
break;
if (i < count)
value |= input[i] << 16;
output += itoa64[(value >> 12) & 0x3f];
if (i++ >= count)
break;
output += itoa64[(value >> 18) & 0x3f];
} while (i < count);
return output;
}
private byte[] GetByteArraysAppended(byte[] partOne, byte[] partTwo)
{
var parts = partOne.ToList();
parts.AddRange(partTwo);
var result = parts.ToArray();
return result;
}
private byte[] GetHash(byte [] bytesToHash)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
var hash = md5.ComputeHash(bytesToHash);
return hash;
}

Windows form c#, encryption and adding additional character

How do I encrypt passwords in such a way that it not only changes the characters of the password but also add extra characters. For example a password as "ABC" would become "12345" instead of "123". Another way is that for each character, the key shift is different. Below are my codes.
class CipherMachine
{
static private List<char> Charset =
new List<char>("PQOWIEURYTLAKSJDHFGMZNXBCV"
+ "olpikmujnyhbtgvrfcedxwszaq"
+ "1597362480"
+ "~!##$%^&*()_+"
+ "PQOWIEURYTLAKSJDHFGMZNXBCV"
+ "olpikmujnyhbtgvrfcedxwszaq"
+ "1597362480"
+ "~!##$%^&*()_+");
static private int Key = 39;
//static private int Length = 0;
static public string Encrypt(string plain)
{
string cipher = "";
foreach (char i in plain)
{
cipher += Charset.ElementAt(Charset.IndexOf(i) + Key);
//cipher += Charset.ElementAt(Charset.IndexOf(i) + Length);
}
return cipher;
}
static public string Decrypt(string cipher)
{
string plain = "";
foreach (char i in cipher)
{
plain += Charset.ElementAt(Charset.LastIndexOf(i) - Key);
//plain += Charset.ElementAt(Charset.LastIndexOf(i) - Length);
}
return plain;
}
}
}
Lines that are commented out are what I thought I could do but it turned out wrong.
You have made the string double length so that the + Key and - Key works, but you ought to have one string of all characters and then WRAP the index (so that if the index goes beyond the length of the string, it wraps back to the beginning). You can achieve this with the % modulus operator:
static private List<char> Charset =
new List<char>("PQOWIEURYTLAKSJDHFGMZNXBCV"
+ "olpikmujnyhbtgvrfcedxwszaq"
+ "1597362480"
+ "~!##$%^&*()_+");
int length = Charset.Count();
// to encrypt
int key = 24;
char unencryptedChar = 'P';
int unencryptedIndex = Charset.IndexOf(unencryptedChar);
int encryptedIndex = (unencryptedIndex + key) % length;
char encryptedChar = Charset.ElementAt(encryptedIndex);
// to unencrypt
int encryptedIndex = Charset.IndexOf(encryptedChar);
int unencryptedIndex = (encryptedIndex - key + length) % length;
char unencryptedChar = Charset.ElementAt(unencryptedIndex);
When you subtract the key in the second part, the index goes negative, and modulus won't work properly on a negative, so we add the length (though this only works if the key is smaller than the length).

Need to convert string/char to ascii values

I need to convert char to hex values. Refer to the Ascii table but I have a few examples listed below:
char 1 = 31
2 = 32
3 = 33
4 = 34
5 = 35
A = 41
a = 61 etc
Therefore string str = "12345";
Need to get the converted str = "3132333435"
I think this is all you'll need:
string finalValue;
byte[] ascii = Encoding.ASCII.GetBytes(yourString);
foreach (Byte b in ascii)
{
finalValue += b.ToString("X");
}
More info on MSDN: http://msdn.microsoft.com/en-us/library/system.text.encoding.ascii.aspx
Edit: To Hex:
string finalValue;
int value;
foreach (char c in myString)
{
value = Convert.ToInt32(c);
finalValue += value.ToString("X");
// or finalValue = String.Format("{0}{1:X}", finalValue, value);
}
// use finalValue
string.Join("", from c in "12345" select ((int)c).ToString("X"));
string s = "abc123";
foreach(char c in s)
{
Response.Write((int)c + ",");
}
To get it in a single line, and more readable (imo)
var result = "12345".Aggregate("", (res, c) => res + ((byte)c).ToString("X"));
this returns "3132333435", just as you requested :)

Categories