I\'ve been looking for a Classic ASP script that allows me to hash a string using the MD5 algorithm. I need to match this hashed string against the same string in an ASP.NET
The hash computation itself is not your problem. You're using UTF-8 in .net, and ANSI/Latin1 in asp classic.
A hash algorithm operates on a sequence of bytes, not on a string. Thus you first need to convert the string to a sequence of bytes first, a process called encoding. Common choices are ANSI(The locale dependent legacy encoding on windows), UTF-8 and UTF-16 LE.
First choose an encoding, and use that consistently on both platforms. I recommend UTF-8, which on .net is accessed via Encoding.UTF.GetBytes()
. You'll need to search for UTF-8+asp classic to figure out how to use from there. Since UTF-8 encoding is a common problem, I'm sure you'll find something.
I suspect your asp classic code uses ANSI, but I strongly recommend not using it, since it only supports a small subset of possible characters, and is locale dependent.
You could wrap the .NET MD5 hashing code in a COM-visible assembly. Then you can deploy and use the same exact MD5 hashing code on your ASP.NET and classic ASP sites.
With this function you can hash the plain text into:
SHA1, SHA256, SHA384, SHA512, MD5, RIPEMD160
If you need more you can find it in: System.Security.Cryptography Namespace
Function Hash(HashType, PlainText)
On Error Resume Next
With CreateObject("ADODB.Stream")
.Open
.CharSet = "Windows-1252"
.WriteText PlainText
.Position = 0
.CharSet = "UTF-8"
PlainText = .ReadText
.Close
End With
Set UTF8Encoding = CreateObject("System.Text.UTF8Encoding")
Dim PlainTextToBytes, BytesToHashedBytes, HashedBytesToHex
PlainTextToBytes = UTF8Encoding.GetBytes_4(PlainText)
Select Case HashType
Case "sha1": Set Cryptography = CreateObject("System.Security.Cryptography.SHA1Managed")
Case "sha256": Set Cryptography = CreateObject("System.Security.Cryptography.SHA256Managed")
Case "sha384": Set Cryptography = CreateObject("System.Security.Cryptography.SHA384Managed")
Case "sha512": Set Cryptography = CreateObject("System.Security.Cryptography.SHA512Managed")
Case "md5": Set Cryptography = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
Case "ripemd160": Set Cryptography = CreateObject("System.Security.Cryptography.RIPEMD160Managed")
End Select
Cryptography.Initialize()
BytesToHashedBytes = Cryptography.ComputeHash_2((PlainTextToBytes))
For x = 1 To LenB(BytesToHashedBytes)
HashedBytesToHex = HashedBytesToHex & Right("0" & Hex(AscB(MidB(BytesToHashedBytes, x, 1))), 2)
Next
Hash = LCase(HashedBytesToHex)
If Err.Number <> 0 Then Response.Write(Err.Description)
On Error GoTo 0
End Function
These can be used as follows:
Hash("sha512", "Hello World")
Produces:
2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b
Hash("sha256", "Hello World")
Produces:
a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
Hash("md5", "muñeca")
Produces:
ea07bec1f37f4b56ebe368355d1c058f
If you want exactly what .Net does , You can decompile ComputeHash method from HashAlgorithm class(also consider MD5CryptoServiceProvider class) from .Net assembly mscorlib.dll (from the path like this in your computer :C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\mscorlib.dll) and then convert the codes to ASP-Classic. Some good (free)Decompilers are:
1- http://www.reflector.net/
2- http://www.telerik.com/products/decompiler.aspx
The first part of hashing any string is getting a byte array of the string's characters. The byte array created depends on the encoding type used for the string. .Net strings are encoded in UTF-16. I don't recall vbscript's encoding type off the type of my head, but it's probably just ascii or at best UTF-8.
Therefore, to fix your problem, the first thing you need to do is get vbscript to give you a byte array that represents the UTF-16 characters in your string. Then go look for an md5 hash function that expects a byte array directly, instead of a string type.
Unfortunately, even this may not be enough. It's possible that vbscript's lack of native UTF-16 could result in what is normally a minor loss of fidelity in the string input from the user, such that the string in your Classic ASP code is no longer exactly the same characters as the string in your ASP.Net code. If this is the case, the only solution is to change your ASP.Net code to match the Classic ASP encoding, rather than vice versa. This may be the much easier solution anyway. For this to work, you will need to know exactly what character encoding your vbscript code is using. Again, I don't have that information in my head anymore, so you can google it as well as I.
If you are using UTF-8 on both .Net and Classic ASP you should be able to borrow the .Net implementation.
Something like this;
<%
Dim asc, enc, bytes, instr, outstr, pos
instr = "muñeca"
Set asc = CreateObject("System.Text.UTF8Encoding")
Set enc = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
bytes = asc.GetBytes_4(instr)
bytes = enc.ComputeHash_2((bytes))
outstr = ""
'Convert the Byte Array to a Hex string
For pos = 1 To LenB(bytes)
outstr = outstr & LCase(Right("0" & Hex(AscB(MidB(bytes, pos, 1))), 2))
Next
Response.Write outstr
%>
Output:
ea07bec1f37f4b56ebe368355d1c058f
This is the only valid method I've found for Classic ASP because all other implementations assume ANSI encoding and you end up with an incorrect hash.
Credit to: Replicating PHP’s sha1() in VBScript for helping me finally find a solution.