如何对 VBA 中的密码存储执行 unicode 规范化?

How do I perform unicode normalization for password storage in VBA?

我想在 VBA 中存储和比较散列密码。

我读过 How do I properly implement Unicode passwords?,但我不知道从哪里开始。

如何规范化 VBA 中的 unicode 字符串?

我最好在不下载链接 post 所指的 ICU 的情况下执行此操作,因为我希望我的项目不依赖于外部代码。

Windows 提供了一个 built-in 用于标准化字符串,即 NormalizeString function。但是,使用起来可能有点棘手。

这是一个基于上面提供的文档中的 C 示例的实现:

'Declare the function
Public Declare PtrSafe Function NormalizeString Lib "Normaliz.dll" (ByVal NormForm As Byte, ByVal lpSrcString As LongPtr, ByVal cwSrcLength As Long, ByVal lpDstString As LongPtr, ByVal cwDstLength As Long) As Long
'And a relevant error code
Const ERROR_INSUFFICIENT_BUFFER = 122
'And a helper enum
Public Enum NORM_FORM
  NormalizationC = &H1
  NormalizationD = &H2
  NormalizationKC = &H5
  NormalizationKD = &H6
End Enum

'Available normalization forms can be found under https://docs.microsoft.com/en-us/windows/win32/api/winnls/ne-winnls-norm_form
'KD normalization is preferred(  when hashing characters
'If you already have hashes stored, C normalization is least likely to break them
Public Function UnicodeNormalizeString(str As String, Optional norm_form As Byte = NormalizationKD) As String
    If Len(str) = 0 Then 'Zero-length strings can't be normalized
        UnicodeNormalizeString = str
        Exit Function
    End If
    Dim outlenestimate As Long
    'Get an initial length estimate for the string
    outlenestimate = NormalizeString(norm_form, StrPtr(str), Len(str), 0, 0)
    
    Dim i As Long
    'Try 10 times
    For i = 1 To 10
        'Initialize buffer
        UnicodeNormalizeString = String(outlenestimate, vbNullChar)
        'Get either the normalized string, or a new length estimate
        outlenestimate = NormalizeString(norm_form, StrPtr(str), Len(str), StrPtr(UnicodeNormalizeString), outlenestimate)
        If outlenestimate > 0 Then 'We got the normalized string
            'Truncate off the unused characters
            UnicodeNormalizeString = Left(UnicodeNormalizeString, outlenestimate)
            Exit Function
        Else
            If Err.LastDllError <> ERROR_INSUFFICIENT_BUFFER Then
                Exit For 'An unexpected error occurred
            End If
            outlenestimate = outlenestimate * -1 'Use the new length estimate, try again
        End If
    Next
    Err.Raise 5000, Description:="Failure to normalize unicode string"
End Function

一旦你声明了规范化函数,在散列之前总是运行你的密码:

If SomeHashFun(UnicodeNormalizeString(MyPassword)) = SomeHashedPassword Then
   'We are in!
End If