Search code examples
phplaravelasp-classicbase64sha512

Translate SHA512 Hash function from Classic Asp to php/Laravel


I need to check asp-generated passwords in php/Laravel. Could you help me to translate this asp code used to generate those passwords?

password = "xxx"
salt = "yyy"
    
saltedPassword = salt & password
    
Set objUnicode = CreateObject("System.Text.UnicodeEncoding")
arrByte = objUnicode.GetBytes_4(saltedPassword)
    
Set objSHA512 = Server.CreateObject("System.Security.Cryptography.SHA512Managed") 
strHash = objSHA512.ComputeHash_2((arrByte))
    
'Ref: http://stackoverflow.com/questions/1118947/converting-binary-file-to-base64-string
Dim xml: Set xml = CreateObject("MSXML2.DOMDocument.3.0")
xml.LoadXml "<root />"
xml.documentElement.dataType = "bin.base64"
xml.documentElement.nodeTypedValue = strHash
ToBase64String = Replace(xml.documentElement.Text,VbLf, "") 

Response.Write "<p>" & ToBase64String & "</p>"

I tried with this:

$password = 'xxx';
$salt = 'yyy';
$saltedpass = $salt.$password;
dd( base64_encode( hash('sha512', $saltedpass, true) ) );

but I get different strings.


Solution

  • Here's my go to ASP hashing function for anyone looking to do fast and simple hashing in Classic ASP. It allows you to hash as MD5, SHA1, SHA256, SHA384 and SHA512, as well as encode as Hex or Base64.

    UPDATE I've also included an option to specify a character set too (Unicode or UTF8).

    Function Hash(ByVal Input, HashAlgorithm, CharSet, Encoding)
        
        ' Select the System.Security.Cryptography value.
        
        Select Case uCase(HashAlgorithm)
        
            Case "MD5"
            
                HashAlgorithm = "MD5CryptoServiceProvider"
                
            Case "SHA1"
            
                HashAlgorithm = "SHA1CryptoServiceProvider"
                
            Case "SHA2","SHA256"
            
                HashAlgorithm = "SHA256Managed"
                
            Case "SHA384"
            
                HashAlgorithm = "SHA384Managed"
                
            Case "SHA5","SHA512"
            
                HashAlgorithm = "SHA512Managed"
                
            Case Else
            
                HashAlgorithm = "SHA1CryptoServiceProvider"
        
        End Select
        
        ' Convert the input to bytes if not already.
                    
        If NOT VarType(Input) = 8209 Then
                        
            Dim CS : Set CS = Server.CreateObject("System.Text." & CharSet & "Encoding")
            
                Input = CS.GetBytes_4(Input)
                                                
            Set CS = Nothing
            
        End If
        
        ' Perform the hash.
                    
        Dim hAlg : Set hAlg = Server.CreateObject("System.Security.Cryptography." & HashAlgorithm)
        Dim hEnc : Set hEnc = Server.CreateObject("MSXML2.DomDocument").CreateElement("encode")
            
            Encoding = lCase(Encoding)
            
            If Encoding = "base64" OR Encoding = "b64" Then
            
                hEnc.dataType = "bin.base64"
            
            Else
            
                hEnc.dataType = "bin.hex"
            
            End If
            
            hEnc.nodeTypedValue = hAlg.ComputeHash_2((Input))
            Hash = hEnc.Text
            
            Hash = Replace(Hash,VBlf,"")
                
        Set hEnc = Nothing
        Set hAlg = Nothing
        
    End Function
    
    Dim password, salt, saltedPassword
    
    password = "xxx"
    salt = "yyy"
    
    saltedPassword = salt & password
    
    Response.Write(Hash(saltedPassword,"SHA512","Unicode","Base64"))
    

    In this example, I've set it to match your code, so it's using System.Text.UnicodeEncoding to get the bytes (although UTF8 should be used by default, it's why your PHP code was returning a different Base64 string), and Hash = Replace(Hash,VBlf,"") is needed as bin.base64 almost always includes a line feed, but PHP never does. This is the Base64 output:

    RLW8OiWU7AN3zhc3Avo7u7OOMjUybf8p8R98dafTPJJPCwfKbxd7soEEZlpXU4CmJ2a4HpGhnLPQFf7at1+yxA==

    ...which matches the Base64 output generated by your ASP code.


    Now to achieve the same in PHP, simply use mb_convert_encoding with UTF-16LE when joining the salt and password:

    $password = 'xxx';
    $salt = 'yyy';
    $saltedpass = mb_convert_encoding($salt.$password,'UTF-16LE');
    
    echo(base64_encode(hash('sha512',$saltedpass,true)));
    

    The PHP hash function will behave the same as using System.Text.UnicodeEncoding in Classic ASP. I don't have Laravel installed, so I could only test using echo, print or var_dump, but not dd, here's the Base64 output in PHP:

    RLW8OiWU7AN3zhc3Avo7u7OOMjUybf8p8R98dafTPJJPCwfKbxd7soEEZlpXU4CmJ2a4HpGhnLPQFf7at1+yxA==

    They're an exact match.