在VB6中散列这种复杂结构的最佳方法是什么?

时间:2009-09-21 12:50:29

标签: vb6 hash

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

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值放在一起。
  4. 我无法发布我的代码,因为它严重依赖于实用程序类来进行序列化,但是如果有人想看到它,那么我会发布它。

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

    修改

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

    1. 很短。这就是为什么我认为32位最合适,因为它可以在屏幕上呈现为10位十进制数。通过电话阅读和输入,这是简单,快速和明确的。
    2. 所有 派生数据结构中的字段,无需额外的人工密钥或任何其他技巧。
    3. 查找,唯一性测试或将ExampleData实例存储在任何类型的集合中都不需要散列,但仅用于上述一个目的。

4 个答案:

答案 0 :(得分:3)

你能使用CRC32吗? Steve McMahon有an implementation。将其与一些base32编码相结合,你就可以通过手机阅读短文。

答案 1 :(得分:0)

你可能会过度思考它,或者我不理解这个问题。你基本上可以哈希(CStr(Salt)+ Name + CStr(ValidOn)+ Anyotherstrings)。

没有特别需要经历序列化为字节数组和异或值的过程。事实上,以这种方式将值组合在一起更有可能在您不打算的情况下创建哈希冲突。

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

答案 2 :(得分:0)

编辑:此问题现在已经过编辑,以澄清目标是检测输入错误,而不是最大限度地减少完全不同的值之间的冲突。在这种情况下,Dan F's answer是最好的恕我直言,而不是我在下面提供的(尽管很棒)。


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

  • 例如this Microsoft有关使用VB6中的CryptoAPI的文章应该可以帮助您入门。
  • 来自mvps.org上Edanmo的
  • this,用于在VB6中散列字符串。

编辑:发表评论。如果您坚持使用32位值,则很难最小化哈希冲突。我的algorithm book建议使用Horner的方法作为一个不错的通用哈希算法。我现在没有时间在VB6中找到更多信息和实现。 CopyMemory可能会有用:)

答案 3 :(得分:0)

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

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