2009-09-21 7 views
0

J'ai les structures suivantes définies (les noms sont anonymisées, mais les types de données sont correctes):Quelle est la meilleure façon de hacher cette structure complexe dans VB6?

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 

Je voudrais générer un code de hachage 32 bits pour une instance ExampleData. La minimisation des collisions de hachage est importante, la performance et l'ordre des données n'est pas important.

Jusqu'à présent, j'ai obtenu (en pseudocode):

  1. serialise tous les membres dans un tableau d'octets.
  2. Parcourez le tableau d'octets en lisant 4 octets à la fois dans une valeur Long.
  3. XOR toutes les valeurs Long ensemble.

Je ne peux pas vraiment publier mon code, car il dépend fortement des classes d'utilitaires pour effectuer la sérialisation, mais si quelqu'un veut le voir, je le publierai.

Est-ce que ce sera OK, ou quelqu'un peut-il suggérer une meilleure façon de le faire?

EDIT:

Ce code est utilisé pour mettre en œuvre une partie d'un système de licences de logiciels. Le but du hachage est de confirmer si les données entrées par l'utilisateur final sont égales aux données saisies par le technicien de support technique. Le hachage doit donc:

  1. Soyez très court. C'est pourquoi j'ai pensé que 32 bits seraient les plus appropriés, car ils peuvent être affichés sous la forme d'un nombre décimal à 10 chiffres à l'écran. C'est facile, rapide et sans ambiguïté à lire sur le téléphone et tapez.
  2. DERIVENT de tous les champs dans la structure de données, sans clés supplémentaires artificiels ou tout autre supercherie.

Le hachage n'est pas nécessaire pour la recherche, le test unique, ou pour stocker ExampleData cas dans tout type de collection, mais seulement pour un but décrit ci-dessus.

+0

Les valeurs de hachage sont utilisées pour accélérer la recherche de données. Si la performance n'est pas un problème, pourquoi voulez-vous le surcoût ajouté? –

+0

Aha! L'édition rend la question beaucoup plus claire. Vous essayez de détecter les petites erreurs de frappe, pas de minimiser les collisions entre des données totalement différentes. Dans ce cas, le CRC devrait être parfait. – MarkJ

Répondre

3

Pouvez-vous utiliser le CRC32? Steve McMahon a an implementation. Combinez cela avec un peu de codage base32 et vous avez quelque chose de suffisamment court pour lire par téléphone.

+0

CRC32 ressemble à la solution la plus pratique, merci Dan. –

+0

+1 Le code de Steve McMahon est toujours excellent, et maintenant la question a été clarifiée CRC est clairement un bon choix. Vous avez accidentellement lié au code Vb.NET - j'ai édité votre réponse pour lier à la version VB6 de Steve McMahon à la place. – MarkJ

+0

Merci Mark. Ce n'était pas difficile de trouver le bon code de toute façon. :-) –

0

Vous pensez peut-être trop, ou je ne comprends pas le problème. Vous pourriez essentiellement juste hash (CStr (Salt) + Nom + CStr (ValidOn) + Anyotherstrings).

Il n'est pas particulièrement nécessaire de passer par le processus de sérialisation en tableau d'octets et en valeurs XOR. En effet, il est plus probable que la combinaison de valeurs XORing de cette façon crée des collisions de hachage lorsque vous ne les envisagez pas.

Modifier: Je pense que je comprends maintenant. Vous créez votre propre valeur de hachage en XORing les données ensemble? C'est malheureusement assez susceptible de provoquer des collisions. Je sais que VB6 n'inclut aucun algorithme de hachage, ainsi vous pouvez importer et employer quelque chose comme Phil Fresle's SHA256 implementation.

+0

Toutes les données dans les structures doivent contribuer au hachage d'une manière ou d'une autre. Peu m'importe comment j'accomplis cela tant que les collisions sont minimisées. Le tableau d'octets et XOR est simplement mon premier coup à une solution. –

0

EDIT: la question a maintenant été modifiée pour préciser que l'objectif est de détecter les erreurs de typage, et non de minimiser les collisions entre des valeurs totalement différentes. Dans ce cas Dan F's answer est le meilleur à mon humble avis, pas mon offre ci-dessous (merveilleux si c'est).


Vous pouvez utiliser le Microsoft CryptoAPI plutôt que de rouler votre propre algorithme de hachage.

  • Par exemple this L'article de Microsoft sur l'utilisation de CryptoAPI de VB6 devrait vous aider à démarrer.
  • Ou this d'Edanmo sur mvps.org pour le hachage d'une chaîne dans VB6.

EDIT: commentaire suivant. Si vous insistez sur une valeur 32 bits, il sera difficile de minimiser les collisions de hachage. Mon algorithm book suggère d'utiliser la méthode de Horner comme un algorithme de hachage général décent. Je n'ai pas le temps maintenant de trouver plus d'informations et d'implémenter dans VB6. CopyMemory serait probablement utile :)

+0

Bonne suggestion, mais je ne veux vraiment qu'une valeur de 32 bits. Pardon! –

0

Considérant que la performance n'est pas un objectif, si la taille du fichier n'est pas importante et que vous voulez une valeur unique pour chaque élément. Ajoutez simplement un champ d'identification. Ce type de données est une chaîne. Utilisez ensuite cette fonction pour générer un GUID. Ce sera un identifiant unique. Utilisez-le comme une clé pour un dicton ou une collection.

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

Je pense que vous avez mal compris mes exigences - pas étonnant parce que je n'ai pas donné beaucoup de détails. J'ai ajouté plus d'informations à la question qui devrait clarifier. –

Questions connexes