0

Most of the topics I have read on this show comparing a password to a hashed/salted password. That is not my use case. I need to read a hashed/salted password out of an xml file and then use that to log into a Sql database. I will need to do this from a Windows Service. I am first unsure how to read that entry in the XML file and then how to "decrypt" it?

The GenerateSaltForPassword and ComputePasswordHash functions come directly from This SO post:

private int GenerateSaltForPassword()
        {
            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
            byte[] saltBytes = new byte[4];
            rng.GetNonZeroBytes(saltBytes);
            return (((int) saltBytes[0]) << 24) + (((int) saltBytes[1]) << 16) + (((int) saltBytes[2]) << 8) +
                   ((int) saltBytes[3]);
        }

        private byte[] ComputePasswordHash(string password, int salt)
        {
            byte[] saltBytes = new byte[4];
            saltBytes[0] = (byte) (salt >> 24);
            saltBytes[1] = (byte) (salt >> 16);
            saltBytes[2] = (byte) (salt >> 8);
            saltBytes[3] = (byte) (salt);

            byte[] passwordBytes = UTF8Encoding.UTF8.GetBytes(password);

            Byte[] preHashed = new Byte[saltBytes.Length + passwordBytes.Length];
            System.Buffer.BlockCopy(passwordBytes, 0, preHashed, 0, passwordBytes.Length);
            System.Buffer.BlockCopy(saltBytes, 0, preHashed, passwordBytes.Length, saltBytes.Length);

            SHA1 sha1 = SHA1.Create();
            return sha1.ComputeHash(preHashed);
        }

And the XML file is generated by:

 private void btnSave_Click(object sender, System.EventArgs e)
        {
            int salt = GenerateSaltForPassword();

            string fileName = System.IO.Path.Combine(Application.StartupPath, "alphaService.xml");
            XDocument doc = new XDocument();
            XElement xml = new XElement("Info",
                new XElement("DatabaseServerName", txtServerName.Text),
                new XElement("DatabaseUserName", txtDatabaseUserName.Text),
                new XElement("DatabasePassword", ComputePasswordHash(txtDatabasePassword.Text, salt)),
                new XElement("ServiceAccount", txtAccount.Text),
                new XElement("ServicePassword", ComputePasswordHash(txtServicePassword.Text, salt)));

            doc.Add(xml);
            doc.Save(fileName);
        }
Community
  • 1
  • 1
user2471435
  • 1,644
  • 7
  • 35
  • 62
  • 2
    If I understand correctly your requirement, you can't. Hashing is a one way process, meaning that you cannot ("programatically") recover (or decrypt) the original value. That's why it's being used for storing passwords. – Andrei V Feb 20 '14 at 14:56
  • I don't understand. If its used for storing passwords, there must be a way to than use that password. What should have I done? Anyway, how can I extract that value out of the XML? – user2471435 Feb 20 '14 at 15:03
  • Reading it is simple but the end result is useless. You'll end up with a hash of the actual password which you will not be able to use for connecting. To read it, do something like this: `XDocument doc = XDocument.Load(pathToXml"); string password = doc.Descendants("DatabasePassword").FirstOrDefault().Value;`. – Andrei V Feb 20 '14 at 15:10

1 Answers1

3

As Andrei correctly stated, the whole point of hashing password is so that the password cannot be retrieved. This is a pretty standard technique to help protect in case password file gets stolen (by hackers). The way this file is used is when user is trying to authenticate, salt is read from DB (or in your case XML), added to entered password same way as when password was set (in your code it is appended to password bytes), and then resulting hash is compared to stored hash. If same, user entered correct password, otherwise incorrect password. So password validation can be done, but password itself cannot be recovered.

Now, if no salt or weak salt is used, it may be possible to reverse hash back using rainbow tables, but this is more of a hacking technique and not practical for your purposes.

So short of it, you can't recover password from hash as that's the reason why it is hashed in the first place.

LB2
  • 4,802
  • 19
  • 35
  • Thank you. This is part of a setup/configuration utility. So how do I accomplish the goal of not storing the password in clear test in an XML file and then using it to set up the connection string in the installed Windows service? – user2471435 Feb 20 '14 at 15:18
  • Going a bit outside the box: have you considered using trusted connection (if it is SQLServer) for authentication? If trusted is not an option, then you need to look into encryption rather than hashing, and encrypt your password in storage. Be careful there since you need to store the key somewhere to decrypt, and if you do it in the code, it can be easily retrieved with utilities like RedGate's .NET Reflector or JetBrains' dotPeak. [This article](http://msdn.microsoft.com/en-us/library/zhhddkxy(v=vs.100).aspx) may help. – LB2 Feb 20 '14 at 15:26
  • I am trying to look into encryption here>/a> – user2471435 Feb 20 '14 at 16:02
  • Have you looked through the article in a link I posted in the comment? – LB2 Feb 20 '14 at 16:03
  • Yes, please see my comment there. I can't store it a config file. There are two executables, the configuration utility which stores the password and then an installed Windows Service that has to read it. That's why I thought of using the XML file. – user2471435 Feb 20 '14 at 18:34