CryptoSys Home > API > Using htpasswd passwords with 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 is not the subject of this page (but we do have free code that does it - see crypt3 password encryption function). 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

For more information or to comment on this page, please send us a message.

This page last updated 15 August 2025.