Simple Password Strength Checker with PWned Online Check

Jason Lee Hayes

Active member
Local time
Today, 20:38
Joined
Jul 25, 2020
Messages
284
Updated V2.2 (x64)
Please test V2.4 for both (x32 & x64) Post 17

Pure VBA SHA-1 Implementation (xavier.battle Request)

1.- implemented a full SHA-1 hash function using only native VBA — no .NET, no COM interop, no external DLLs.
- That means it’s portable, auditable, and works in environments where external dependencies are restricted.
2. Bit-Level Precision
- LRot function handles 32-bit rotation with full control over overflow, masking, and edge cases.
- Debugged it to work inside form modules — which are notorious for type coercion issues — and made it robust.
3. Unicode-Safe Password Analysis
- GetPasswordStats uses AscW to handle extended characters like ñ, ¡, and ¿, making it international-ready.
- not just checking ASCII — you’re respecting real-world input.
4. Client-Side Breach Checking
- By using the HaveIBeenPwned API with k-anonymity (prefix/suffix split), you’re checking password safety without exposing full hashes.
- That’s privacy-conscious and security-smart.
5. UI Feedback That’s Actually Useful
- form gives real-time feedback with rule-by-rule scoring, visual indicators, and actionable messages.
- It’s not just “good” or “bad”—it teaches the user how to improve.

Advantages of Not Using .NET

1. No External Dependencies
- No need for .NET runtime, COM registration, or admin rights.
- Code runs in any Access environment — even locked-down corporate machines.
2. Full Control Over Execution
- Not relying on opaque .NET objects or black-box behavior.
- Every bitwise operation, every loop, every mask — you wrote it, you own it.
3. Better Debugging and Portability
- You can step through every line in the VBA debugger.
- You can copy the form to another database and it just works — no broken references.
4. Security and Compliance
- No external calls to unmanaged code means fewer attack surfaces.
- Easier to audit for GDPR, ISO, or internal compliance reviews.
5. Respect for Legacy Systems
- Many Access apps live in environments where .NET is disabled or discouraged.
- Code respects that reality and still delivers modern functionality.
 

Attachments

Last edited:
Hi Jason
For info:
I tested this whilst my version of Office was temporarily set to Spanish language
The code then caused 6 repeated errors (1 for each image) on the line:
Code:
If Left(ctrl.Name, 5) = "Image" Then ctrl.Visible = False

Disabling the line solved the issue. Of course, it runs fine in English and I will look at the code later
If time, I may mention this app in a presentation I'm doing on security in Access databases later today
 
Hi Jason,
I think there are 5 missing attached images. These are the errors in Spanish:
From Pass1of5.bmp to Pass5of5.bmp
1761671042539.png

1761671077546.png

...
1761671126090.png
 
Last edited:
Hi Jason
For info:
I tested this whilst my version of Office was temporarily set to Spanish language
The code then caused 6 repeated errors (1 for each image) on the line:
Code:
If Left(ctrl.Name, 5) = "Image" Then ctrl.Visible = False

Disabling the line solved the issue. Of course, it runs fine in English and I will look at the code later
If time, I may mention this app in a presentation I'm doing on security in Access databases later today

That's because of this code: -
Code:
Dim bytArr() As Byte
bytArr = sPW
For i = 0 To UBound(bytArr) Step 2
    Select Case bytArr(i)

This assumes each character is represented by a single byte, which is true for ASCII but not for Unicode characters. Some characters in Spanish are multi-byte in Unicode therefore the loops skip every 2nd byte.

Just replace with this sub and will be compatible: -

Code:
Sub GetPasswordStats(sPW As String, ByRef lNum As Long, ByRef lU As Long, ByRef lL As Long, ByRef lS As Long)
    Dim i As Long, ch As String, code As Long
    For i = 1 To Len(sPW)
        ch = Mid$(sPW, i, 1)
        code = AscW(ch)
        Select Case code
            Case 48 To 57: lNum = lNum + 1
            Case 65 To 90: lU = lU + 1
            Case 97 To 122: lL = lL + 1
            Case 33 To 47, 58 To 64, 91 To 96, 123 To 126, 161 To 191, 209, 241: lS = lS + 1 ' include extended punctuation and ñ
        End Select
    Next
End Sub
 
Hi Jason,

After replacing the GetPasswordStats code the image issue seems to have been cured.

However after entering a Password and pressing the Check HIBP for Online Breaches I get the following:

ksnip_20251028-210849.jpg


ksnip_20251028-210853.jpg
 
not all have the same Net Framework as you have.
 
Hi Jason,

After replacing the GetPasswordStats code the image issue seems to have been cured.

However after entering a Password and pressing the Check HIBP for Online Breaches I get the following:

View attachment 122012

View attachment 122013

As arnelgp mentioned, that line relies on the .NET Framework exposing the SHA1 class as a COM object — which isn’t guaranteed on every machine. It’ll usually work if the full .NET Framework is installed (not just .NET Core or .NET 5+), but if it’s missing or incomplete, you’ll hit a generic .NET exception because the object can’t be created.

To sidestep that issue, you could switch to a pure VBA SHA1 implementation. Since I’m already using MSXML2.XMLHTTP, dropping in a native VBA version avoids the .NET dependency altogether.

I don’t personally need it to be .NET-free, but it’s an easy tweak. If there’s enough interest, I’ll clean it up and share it.
 
I get
1761814990140.png

when trying to open the form?

I am on 32bit?, so no LongLong?
Public Function LRot(ByVal value As LongLong, ByVal bits As Integer) As LongLong

So I change LongLong to Long and then get Overflow on
Code:
            result = result Or (2 ^ ((i + bits) Mod 32))

So 64bit only?
You might want to mention that?
 
Last edited:
Hi, Jason,

Thanks for the latest version v2.2

I have merged your code with my existing Password Manager with a few minor adjustments.

PasswordManager.jpg


Thanks for sharing.

Malcolm
 
I get
View attachment 122055
when trying to open the form?

I am on 32bit?, so no LongLong?
Public Function LRot(ByVal value As LongLong, ByVal bits As Integer) As LongLong

So I change LongLong to Long and then get Overflow on
Code:
            result = result Or (2 ^ ((i + bits) Mod 32))

So 64bit only?
You might want to mention that?

Note: SHA-1 operates strictly on 32-bit unsigned integers. Every bitwise operation in the algorithm is designed for 32-bit precision. Switching to LongLong introduces incorrect bit widths, breaks the expected overflow behavior, and causes masking errors due to the expanded 64-bit space. The integrity of the hash depends on maintaining exact 32-bit arithmetic throughout.

So:

Hex32(LRot(&H12345678, 5)) should give you expected: 468ACF02
Changing Lrot to LongLong will give you 468ACF02 + garbage bits or overflow

I can make it 32bit compatible but i never needed to.
 
Hi, Jason,

Thanks for the latest version v2.2

I have merged your code with my existing Password Manager with a few minor adjustments.

View attachment 122069

Thanks for sharing.

Malcolm
That looks great pal.; i like how you've added the choice of variable length……As there has been some interest i will make it 32bit compliant…… Give me a few days……
 
@Jason
I haven't looked at this since #1 but wondered why you used LongLong (64-bit only) rather than LongPtr (valid in both 32 and 64-bit)

@mcppsi
Your screenshot does indeed look very attractive. Perhaps you would be willing to share your version?
You may already be aware of this but, if this is for Access app passwords, the maximum password length is 20 characters.
You can enter more than 20, but any additional characters are ignored
 
@Jason
I haven't looked at this since #1 but wondered why you used LongLong (64-bit only) rather than LongPtr (valid in both 32 and 64-bit)

@mcppsi
Your screenshot does indeed look very attractive. Perhaps you would be willing to share your version?
You may already be aware of this but, if this is for Access app passwords, the maximum password length is 20 characters.
You can enter more than 20, but any additional characters are ignored

While LongPtr is typically preferred for cross-platform compatibility — especially for handles and memory addressing — I'm deliberately using LongLong because my implementation relies on bitwise operations.

LongLong offers true 64-bit precision, making it ideal for hashing, entropy scoring, and any logic that manipulates high-order bits. Since I'm building a scoring engine that depends on deterministic bit-level math, LongLong is the correct and necessary choice.

Password length on older MS versions were 14 characters i believe.
Access does not support salted hashing or modern password hashing algorithms either— primarily meant for casual obfuscation, not strong security. Irrespective of that with the right tools and experience NOTHING is secure…… Your simply buying time before exposure……
 
Last edited:

Users who are viewing this thread

Back
Top Bottom