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
For more information or to comment on this page, please send us a message.
This page last updated 15 August 2025.