Amadiere.com

Fourteen and a half crazy frog burpers

10th February 2011

C#.NET & Classic ASP Password Hashing

Filed under: ASP.NET,C#,Classic ASP — Tags: , , , , — Alex Holt @ 9:02 pm

One of the things I’ve recently been working on is a solution to allow both a .NET application and a legacy VBScript / Classic ASP to be able to validate a specific username / password combination, comparing two hashed passwords. In the process, I discovered (with the help of Google and StackOverflow) that accessing .NET objects from Classic ASP isn’t really all that hard! But to the issue at hand: Password Hashing! Sorting this out from the .NET side was relatively easy. For the purpose of this post, here is roughly what I have at the moment.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
 
namespace Amadiere.Com.Utilities
{
    public static class Cryptography
    {
        /// <summary>
        /// Encrypts a password based on the passed in Encryption method (SHA512Managed is a good starting
        /// point if you don't know which to use).
        /// </summary>
        /// <remarks>
        /// The passwordSalt parameter is required to ensure that rainbow tables cannot be used to
        /// lookup all usernames if the salt is discovered. This salt is OK to store in the database,
        /// along with the hashedPassword generated by this function.
        /// </remarks>
        /// <param name="password">The password to be encrypted.</param>
        /// <param name="passwordSalt">The individual grain of salt for that password.</param>
        /// <param name="method">The method by which to encrypt.</param>
        /// <returns>An string representing the hashed password (88 characters long).</returns>
        public static string Hash(string password, string passwordSalt, HashMethods method)
        {
            string siteWideSalt = "THIS IS A SITE WIDE SALT, BUT COULD BE A GUID";
            string encryptedPassword;
            switch (method)
            {
                default:
                    encryptedPassword = HashSHA512Managed(siteWideSalt + password + passwordSalt);
                    break;
            }
            return encryptedPassword;
        }
 
        /// <summary>
        /// One-way encrypts the password into oblivion. If the same password and salt are provided, the
        /// same end string will be churned out the other end of this sausage machine.
        /// </summary>
        /// <see cref="http://msdn.microsoft.com/en-us/library/system.security.cryptography.sha512managed.aspx"/>
        /// <example>HashSHA512Managed("bobsYourUncle_SALT-GOES-HERE");</example>
        /// <param name="password">Unencoded pre-salted password.</param>
        /// <returns>An 88 character string, representing the originally encoded password.</returns>
        private static string HashSHA512Managed(string saltedPassword)
        {
            UnicodeEncoding uniEncode = new UnicodeEncoding();
            SHA512Managed sha = new SHA512Managed();
            byte[] bytePassword = uniEncode.GetBytes(saltedPassword);
            byte[] hash = sha.ComputeHash(bytePassword);
            return Convert.ToBase64String(hash);
        }
    }
 
    public enum HashMethods
    {
        SHA512
    }
}

The Classic ASP side of things wasn’t as easy. There are no built in libraries for SHA512 (or in fact, many other password hashing algorithms). So I had a few options on how I was to proceed:

  • Abandon my choice of SHA512 and go with MD5 where there seemed to be a bit more usage in the community. I was reluctant to do this because it isn’t as good as SHA512.
  • Copy some code sample that has been created by someone else, that I either have to accept is OK, or spend a good deal of time understanding it and breaking it down bit by bit.
  • Create a custom COM object in .NET, register it in the GAC and reference that via Classic ASP.
  • Access the .NET functions directly from Classic ASP.

The last option won – because it worked, and because it meant a lot lessĀ maintenanceĀ and praying for things to keep working. This is the code that pretty much does the same as the above .NET code, but in VBScript.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Function Hash(strPassword, strIndividualSalt)
 
  Const strSiteWideSalt = "THIS IS A SITE WIDE SALT, BUT COULD BE A GUID"
  Hash = HashSHA512Managed(strSiteWideSalt & strPassword & strIndividualSalt)
 
End Function
 
Function HashSHA512Managed(saltedPassword)
 
  Dim objMD5, objUTF8
  Dim arrByte
  Dim strHash
  Set objUnicode = CreateObject("System.Text.UnicodeEncoding")
  Set objSHA512 = Server.CreateObject("System.Security.Cryptography.SHA512Managed")
 
  arrByte = objUnicode.GetBytes_4(saltedPassword)
  strHash = objSHA512.ComputeHash_2((arrByte))
 
  HashSHA512Managed = ToBase64String(strHash)
 
End Function
 
Function ToBase64String(rabyt)
 
  'Ref: http://stackoverflow.com/questions/1118947/converting-binary-file-to-base64-string
  Dim xml: Set xml = CreateObject("MSXML2.DOMDocument.3.0")
  xml.LoadXml ""
  xml.documentElement.dataType = "bin.base64"
  xml.documentElement.nodeTypedValue = rabyt
  ToBase64String = Replace(xml.documentElement.Text,VbLf, "")
 
End Function

As you can see in the VBScript example, I can create the .NET objects as I would any other type of object in VBScript, the difference comes in how I use them. Normally, in C#, you’d simply use ComputeHash() and there would be a number of overloads for you to choose from. As VBScript doesn’t have the concept of overloading, you have to use a crazy-mad way of accessing the specific overload you want – using an underscore. I’ve not really come up with a full-proof way of working out which is which (though, if I’m honest, I didn’t try much). I did however find out that they started ComputeHash(), ComputeHash_1() and ComputeHash_2() – I assume the numbers resemble the order they appear in Visual Studio when using intellisense for C# – but trial and error is normally good enough.

Hope this is of use to someone else! If anything, I’m sure I’ll find a need to do this again someday and I’m sure it’ll be useful for then! All this hashing has made me hungry!

Hashing passwords is hard! Let's eat!

Hashing passwords is hard! Let's eat!

7th April 2009

Calculating the Date of Easter Programatically

Filed under: Classic ASP — Tags: , , , — Alex Holt @ 11:25 pm

Every now and then, something really complex comes along and the answer is there on Google. A bit back now, I was asked to create a file for import into the organisations payroll system. The tricky thing was that this had to be an automated procedure that knew the date on which we would be paid.

The rule of thumb is fairly simple: We get paid on the 15th of the month. If this day happens to be a Saturday or Sunday – then it should be the preceding Friday. So sometimes, the 13th or 14th maybe. Bank Holidays? Most bank holidays avoid the 15th of the month without a problem – the exception is Easter. Easter is based on the lunisolar calendar. I had a quick Google, but alas, the Moon didn’t have a web-service, so I was gonna have to do this the hard way!

Having a quick read up about the subject reveals a wealth of complications where, between them, the Gregorian calendar and Christianity just about mess everything up for everyone! Unthoughtful, I agree. But the general rule of thumb is:

Easter and the holidays that are related to it are moveable feasts, in that they do not fall on a fixed date in the Gregorian or Julian calendars (both of which follow the cycle of the sun and the seasons). Instead, the date for Easter is determined on a lunisolar calendar, as is the Hebrew calendar.

In Western Christianity, using the Gregorian calendar, Easter always falls on a Sunday between March 22 and April 25 inclusively.[36] The following day, Easter Monday, is a legal holiday in many countries with predominantly Christian traditions. In Eastern Christianity, which use the Julian calendar for religious dating, Easter also falls on a Sunday between March 22 and April 25 inclusive of the Julian calendar. In terms of the Gregorian calendar, due to the 13 day difference between the calendars between 1900 and 2099, these dates are between April 4 and May 8 inclusive.

I could have settled for programming the relevant dates for the next 40 years, but somehow, that didn’t sit comfortably with me. It was then I stumbled upon a great article (the link no longer works, but it seems the guy knows and is working on updating it – so I’ll leave the link in for now).

To work out the date of Easter Sunday, there is some mathematical algorithms to it after all! (Praise be to science!)

These are the original comments, which are well written and I shan’t be able to improve upon much:

First work out “epact”: the approximate date of the Paschal moon. The number is the approximate number of days before April 19 that a full moon will occur. The number increases by 11 each year because 365 days is equal to 12 lunar cycles of 29.5 days plus 11 days. The 2 is an arbitrary start point based on the state of the moon when they worked out this algorithm is 1582.

“a” and “b” are corrections based on the current century.

The formula was based on the simpler one in use with the Julian calendar, so the first correction is just to make it work with the Gregorian calendar. It is essentially the “missing” leap days in the Gregorian calendar for 1700, 1800, etc, which is 15 for years 1900-2099.

The second correction improves the 19 years = 235 moons approximation.

Then the whole sum is reduced mod 30 to give us the age of the moon in days on April 5th (14 = full)

And a last correction is made in case either the epact is 0 (which would push the date of the moon later than the set limit of 18 April) or it is 1 AND we are in the second half of the 19 year cycle (because that means the previous correction was made already in this cycle but we don’t want to repeat it) In either case we just bump it on 1 because e=2 cannot happen.

Genius! There was a wonderful example function written in a language which wasn’t much use to me, so I converted into a VB Script function that could be called by my script. While the following is written for Classic ASP / VBScript, there is no reason why it can’t be easily turned back into PHP, Java, or a VB or C#.NET function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Function EasterMonday(iYear)
 
  Dim iMonth, iDay, iMoon, iEpact, iSunDay, iGold, iCent, iCorx, iCorz
 
  If IsNumeric (iYear) Then
    iYear = CInt(iYear)
 
    If (iYear &gt;= 1583) And (iYear &lt;= 8702) Then
      iGold = ((iYear Mod 19) + 1) 'the golden number of the year in the 19 year metonic cycle
      iCent = ((Int(iYear / 100)) + 1) 'calculate the century
      iCorx = (Int((3 * iCent) / 4) - 12) 'no. of years in which leap year was dropped in order to keep in step with the sun
      iCorz = (Int((8 * iCent + 5) / 25) - 5) 'special correction to syncronize easter with the moon's orbit
      iSunDay = (Int((5 * iYear) / 4) - iCorx - 10) 'find sunday
      iEpact = ((11 * iGold + 20 + iCorz - iCorx) Mod 30) 'set epact (specifies occurance of full moon

      If (iEpact &lt; 0) Then
        iEpact = iEpact + 30
      End If
 
      If ((iEpact = 25) And (iGold &gt; 11)) Or (iEpact = 24) Then
        iEpact = iEpact + 1
      End If
 
      iMoon = 44 - iEpact 'Find Full Moon

      If (iMoon &lt; 21) Then
        iMoon = iMoon + 30
      End If
 
      iMoon = (iMoon + 7 - ((iSunDay + iMoon) Mod 7)) 'advance to sunday

      If (iMoon &gt; 31) Then
        iMonth = 4
        iDay = (iMoon - 31)
      Else
        iMonth = 3
        iDay = iMoon
      End If
 
      EasterSunday = DateSerial(iYear, iMonth, iDay)
    Else
      EasterSunday = False
    End If
  Else
    EasterSunday = False
  End If
End Function

I’m always amazed by things like this. What initially seemed to me to be an overwhelming task, was solved by a small amount of code. What I thought was entirely based about the moon and how it felt like eclipsing every now and then, can actually be solved by mathematical equations!

I’d think about chalking this up as another victory for science over religion. However, I’m not entirely convinced that science and the stupidity of man didn’t pay part in the confusion in the first place. So I’ll just leave that potentially controversial debate for another time :)

Theme designed & built for Amadiere.com by Alex Holt. Powered by WordPress