如何对 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
我想在 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