CryptoSys API Using htpasswd passwords with CryptoSys API

This page demonstrates VB6/VBA code to create and verify passwords using the Apache `htpasswd' algorithm with SHA-1 and salted SHA-1. It uses the SHA1_StringHexHash and base64 conversion functions from CryptoSys API.

A typical password file might contain entries of the form

sean:{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=
susan:{SSHA}YNHKJFkkauc8jvY7Wur2cJ9bAgiTKs7N
The code below shows how to create the `htpasswd' strings that begin with "{SHA}" or "{SSHA}" and also how to verify a given string with a password.

Just to be clear, the usual htpasswd algorithm uses the crypt3 algorithm, which we don't currently support (but we might if you ask nicely). There is also an Apache "modified" MD5 algorithm (whatever that is) which we don't support either. This code just considers htpasswd strings that begin with "{SHA}" or "{SSHA}".

Public Function Make_htpasswd_sha1(strPassword As String) As String
' Given password, return the htpasswd string in the form "{SHA}"
    Dim nRet As Long
    Dim strDigestHex As String
    Dim strDigestB64 As String
    
    ' Compute hex-encoded SHA-1 digest of password string
    strDigestHex = String(API_MAX_SHA1_CHARS, " ")
    nRet = SHA1_StringHexHash(strDigestHex, strPassword)
    ' Now convert from hex to base64
    strDigestB64 = cnvB64StrFromBytes(cnvBytesFromHexStr(strDigestHex))
    ' Prepend "{SHA}" and return
    Make_htpasswd_sha1 = "{SHA}" & strDigestB64
    
End Function

Public Function Make_htpasswd_salted_sha1(strPassword As String) As String
' Given password, return the htpasswd string in the form "{SSHA}"
    Dim nRet As Long
    Dim strDigestHex As String
    Dim strDigestB64 As String
    Dim strSaltHex As String
    Dim strSalt As String
    
    ' Generate a 4-byte random salt in hex format
    strSaltHex = rngNonceHex(4)
    ' Convert to a 4-byte string
    strSalt = cnvStringFromHexStr(strSaltHex)
    ' Compute hex-encoded SHA-1 digest of (password||salt) string
    strDigestHex = String(API_MAX_SHA1_CHARS, " ")
    nRet = SHA1_StringHexHash(strDigestHex, strPassword & strSalt)
    ' Now convert (digest||salt) from hex to base64
    strDigestB64 = cnvB64StrFromBytes(cnvBytesFromHexStr(strDigestHex & strSaltHex))
    ' Prepend "{SSHA}" and return
    Make_htpasswd_salted_sha1 = "{SSHA}" & strDigestB64
    
End Function

Public Function Verify_htpasswd(strPassword As String, strHtpasswd As String) As Integer
' Returns 0 if OK, 1 if fails and -1 if an error occurred e.g. unsupported.
' Only supports {SHA} and {SSHA} htpasswds.

    Dim nRet As Long
    Dim strDigestHex As String
    Dim strDigestB64 As String
    Dim strPwdHex As String
    Dim strSaltHex As String
    Dim strSalt As String
    
    Verify_htpasswd = 1     ' Guilty until proven innocent
    
    If Left$(strHtpasswd, 5) = "{SHA}" Then
        ' Simple non-salted SHA-1 algorithm, so extract digest from htpasswd string
        strDigestB64 = Mid$(strHtpasswd, 6)
        strDigestHex = cnvHexStrFromBytes(cnvBytesFromB64Str(strDigestB64))
        ' Recompute SHA-1 hash of given password
        strPwdHex = String(API_MAX_SHA1_CHARS, " ")
        nRet = SHA1_StringHexHash(strPwdHex, strPassword)
        If UCase(strPwdHex) = UCase(strDigestHex) Then
            Verify_htpasswd = 0
        Else
            Verify_htpasswd = 1
        End If
        
    ElseIf Left$(strHtpasswd, 6) = "{SSHA}" Then
    
        ' Salted SHA-1 algorithm, so extract (digest||salt) from htpasswd string
        strDigestB64 = Mid$(strHtpasswd, 7)
        strDigestHex = cnvHexStrFromBytes(cnvBytesFromB64Str(strDigestB64))
        If Len(strDigestHex) < 42 Then
            Debug.Print "Invalid htpasswd string"
            Verify_htpasswd = -1
            Exit Function
        End If
        ' Split (digest||salt) into separate hex strings
        strSaltHex = Mid$(strDigestHex, 41)
        strDigestHex = Left$(strDigestHex, 40)
        ' Convert salt from hex into a string
        strSalt = cnvStringFromHexStr(strSaltHex)
        ' Recompute SHA-1 hash of given password + salt
        strPwdHex = String(API_MAX_SHA1_CHARS, " ")
        nRet = SHA1_StringHexHash(strPwdHex, strPassword & strSalt)
        If UCase(strPwdHex) = UCase(strDigestHex) Then
            Verify_htpasswd = 0
        Else
            Verify_htpasswd = 1
        End If
    
    Else
        Debug.Print "Unsupported htpasswd algorithm"
        Verify_htpasswd = -1
        Exit Function
    End If
End Function
The code can be downloaded separately as a text file.

Examples of newly created {SHA} htpasswd strings are

? make_htpasswd_sha1("abc")
{SHA}qZk+NkcGgWq6PiVxeFDCbJzQ2J0=
and
? make_htpasswd_sha1("password")
{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g= 
These values will always be the same for a given password. For that reason, we do not recommend the use of the un-salted SHA-1 password strings. Use the salted ones if you can.

Examples of {SSHA} htpasswd strings with a salt are

? Make_htpasswd_salted_sha1("abc")
{SSHA}i2IK8fsdsFRq6oAg3dU4pVrpM3so3rqD
and
? Make_htpasswd_salted_sha1("password")
{SSHA}y/6RK6tWKwyW3Z+kz1u9uwAGjscz/XRD
Unlike the unsalted variety, these values will always be different, even for the same password. This is more secure. For example:
? Make_htpasswd_salted_sha1("password")
{SSHA}Hnww+GuzW9ySa4HCJm2lqzYucUHlhm9o
? Make_htpasswd_salted_sha1("password")
{SSHA}PF3cjsK6WyPpcD9mA6JSBhQ3+4jUxQwp
? Make_htpasswd_salted_sha1("password")
{SSHA}CAHTDisW6rEHgWDR0bVjcbNlWylbWOBJ

To verify a user password, specify both the password string, as typed by the user, and the htpasswd string. A valid password/htpasswd string combination returns zero.

? Verify_htpasswd("password", "{SSHA}CAHTDisW6rEHgWDR0bVjcbNlWylbWOBJ")
 0 
An incorrect password will return +1
? Verify_htpasswd("bad-password", "{SSHA}CAHTDisW6rEHgWDR0bVjcbNlWylbWOBJ")
 1 
And an unsupported algorithm will return -1
? Verify_htpasswd("password", "YLZzy24Wj6.TU")
Unsupported htpasswd algorithm
-1 

Contact us

To comment on this or ask questions, please contact us.

This page last updated 1 May 2007

Valid HTML 4.01! Valid CSS

Home | Blowfish | Rijndael AES | DES | Triple DES | SHA-1 | SHA-256 | Random numbers | Compression | CryptoSys Manual | Purchase | CryptoSys PKI | Search | Cryptography Software Code | Contact us
Copyright © 2007 D.I. Management Services Pty Limited ABN 78 083 210 584, Sydney, Australia. All rights reserved.
<www.di-mgt.com.au>   <www.cryptosys.net>