在VB6中哈希此复杂结构的最佳方法是什么?

问题描述 投票:0回答:4

我定义了以下结构(名称已匿名,但数据类型正确):

Public Type ExampleDataItem
    Limit As Integer    ' could be any value 0-999
    Status As Integer   ' could be any value 0-2
    ValidUntil As Date  ' always a valid date
End Type

Public Type ExampleData
    Name As String      ' could be 5-20 chars long
    ValidOn As Date     ' could be valid date or 1899-12-30 representing "null"
    Salt As Integer     ' random value 42-32767
    Items(0 To 13) As ExampleDataItem
End Type

我想为ExampleData实例生成32位哈希码。最小化哈希冲突很重要,性能和数据顺序并不重要。

到目前为止,我已经得到(用伪代码):

  1. 将所有成员序列化为一个字节数组。
  2. 循环遍历字节数组,一次将4个字节读入Long值。
  3. 将所有Long值一起异或。

我无法真正发布我的代码,因为它在很大程度上依赖于实用程序类来进行序列化,但是如果有人想看到它,无论我将如何发布它。

这可以吗,或者有人可以建议一种更好的方法吗?

编辑:

此代码用于实现软件许可系统的一部分。哈希的目的是确认最终用户输入的数据是否等于技术支持人员输入的数据。因此,哈希必须:

  1. 非常简短。这就是为什么我认为32位最合适的原因,因为它可以在屏幕上呈现为10位十进制数。通过电话阅读并键入内容非常容易,快速且明确。
  2. 源自all数据结构中的字段,没有额外的人工键或任何其他欺骗手段。

[散列对于查找,唯一性测试或将ExampleData实例存储在任何类型的集合中都是不需要的,而仅出于上述目的。

vb6 hash
4个回答
3
投票
您可以使用CRC32吗?史蒂夫·麦克马洪(Steve McMahon)拥有an implementation。结合一点点base32编码,您就可以通过电话阅读到足够短的内容。

0
投票
如果文件大小不重要,并且您希望每个项目都具有唯一的值,则考虑性能不是目标。只需添加一个ID字段即可。它的数据类型是一个字符串。然后使用此函数生成一个GUID。这将是唯一的ID。将其用作字典或集合的键。

Public Type GUID Data1 As Long Data2 As Integer Data3 As Integer Data4(7) As Byte End Type Public Type GUID2 '15 BYTES TOTAL Data1(14) As Byte End Type Public Declare Function CoCreateGuid Lib "OLE32.DLL" (pGuid As GUID) As Long Public Function GetGUID() As String Dim VBRIG_PROC_ID_STRING As String VBRIG_PROC_ID_STRING = "GetGUID()" Dim lResult As Long Dim lguid As GUID Dim MyguidString As String Dim MyGuidString1 As String Dim MyGuidString2 As String Dim MyGuidString3 As String Dim DataLen As Integer Dim StringLen As Integer Dim i As Integer On Error GoTo error_olemsg lResult = CoCreateGuid(lguid) If lResult = 0 Then MyGuidString1 = Hex$(lguid.Data1) StringLen = Len(MyGuidString1) DataLen = Len(lguid.Data1) MyGuidString1 = LeadingZeros(2 * DataLen, StringLen) & MyGuidString1 'First 4 bytes (8 hex digits) MyGuidString2 = Hex$(lguid.Data2) StringLen = Len(MyGuidString2) DataLen = Len(lguid.Data2) MyGuidString2 = LeadingZeros(2 * DataLen, StringLen) & Trim$(MyGuidString2) 'Next 2 bytes (4 hex digits) MyGuidString3 = Hex$(lguid.Data3) StringLen = Len(MyGuidString3) DataLen = Len(lguid.Data3) MyGuidString3 = LeadingZeros(2 * DataLen, StringLen) & Trim$(MyGuidString3) 'Next 2 bytes (4 hex digits) GetGUID = MyGuidString1 & MyGuidString2 & MyGuidString3 For i = 0 To 7 MyguidString = MyguidString & Format$(Hex$(lguid.Data4(i)), "00") Next i 'MyGuidString contains last 8 bytes of Guid (16 hex digits) GetGUID = GetGUID & MyguidString Else GetGUID = "00000000" ' return zeros if function unsuccessful End If Exit Function error_olemsg: GetGUID = "00000000" Exit Function End Function Public Function LeadingZeros(ExpectedLen As Integer, ActualLen As Integer) As String LeadingZeros = String$(ExpectedLen - ActualLen, "0") End Function


0
投票

EDIT:现在,已经对问题进行了编辑,以澄清目标是检测键入错误,而不是最大程度地减少完全不同的值之间的冲突。在这种情况下,Dan F's answer是最好的恕我直言,不是我下面提供的产品(虽然很棒)。


您可以使用Microsoft CryptoAPI,而不是滚动自己的哈希算法。

    例如,this Microsoft文章中有关从VB6使用CryptoAPI的知识应该可以帮助您入门。
  • 或mvps.org上Edanmo的this,用于在VB6中对字符串进行哈希处理。
  • 编辑:以下评论。如果您坚持使用32位值,则很难最小化哈希冲突。我的algorithm book建议使用霍纳方法作为一种不错的通用哈希算法。我现在没有时间查找更多信息并在VB6中实施。 CopyMemory可能会有用:)

  • 0
    投票
    您可能想得太多,或者我不明白这个问题。您基本上可以只是

    hash(CStr(Salt) + Name + CStr(ValidOn) + Anyotherstrings

    不需要特别进行序列化为字节数组和XORing值的过程。以这种方式对值进行异或运算,更有可能在您不希望它们发生的地方产生哈希冲突。

    编辑:我想我现在明白了。您是通过将数据异或创建自己的哈希值?不幸的是很可能发生碰撞。我知道VB6不包含任何哈希算法,因此您最好导入并使用Phil Fresle's SHA256 implementation之类的东西。

    © www.soinside.com 2019 - 2024. All rights reserved.