使用fnv1a32将byte []转换为0x十六进制字符串

时间:2019-09-22 06:44:19

标签: c# hash

我正在尝试将以下python代码移植到c#

import os
import sys
import ctypes

FNV32_PRIME = 0xB3CB2E29
FNV32_BASIS = 0x319712C3

def uint32(v):
  return ctypes.c_uint32(v).value

def fnv1a_hash(data):
  hval = FNV32_BASIS

  for i in range(0, len(data)):
    hval = uint32(hval ^ data[i])
    hval = uint32(hval * FNV32_PRIME)

  return hval

print("starting")

if len(sys.argv) == 2:
  input_file_path = sys.argv[1]
else: input_file_path = "dvars.txt"

with open(input_file_path, "r") as input_file:
    for dvar_name in input_file:
      dvar_name = dvar_name.rstrip("\r\n")
      dvar_hash_1 = dvar_name.lower() + '\x00'
      dvar_hash_2 = bytearray(dvar_hash_1.encode("ascii"))
      dvar_hash = fnv1a_hash(dvar_hash_2)
      final = "%-30s = 0x%08X" % (dvar_name, dvar_hash)
      print(final)
print("done")

工作正常:

starting
con_gameMsgWindow0MsgTime      = 0xFC60C821

到目前为止,我已经知道了:

    public static class Extensions
    {
        private const UInt32 FnvPrime = 0xB3CB2E29;private const UInt32 FnvOffsetBasis = 0x319712C3;
        public static string ToHashFnv1a32(this string text, Fnv1a32 hasher = null)
        {
            var bytes_encoded = Encoding.UTF8.GetBytes(text); // +'\x00'
            if (hasher is null) hasher = new Fnv1a32(fnvPrime: FnvPrime, fnvOffsetBasis: FnvOffsetBasis);
            var byte_hash = hasher.ComputeHash(bytes_encoded);
            // int decValue = int.Parse(t, System.Globalization.NumberStyles.HexNumber);
            var uint32 = BitConverter.ToUInt32(byte_hash, 0);
            var uint32_hex = string.Format("{0:X}", uint32);
            var uint32_dec = string.Format("{0:D}", uint32);
            var stringg = BitConverter.ToString(byte_hash).Replace("-", "");
            var expected_hex = string.Format("{0:X}", 0xFC60C821);
            var expected_dec = string.Format("{0:D}", 0xFC60C821);
            return byte_hash.ToString(); // 
        }
    }

但是由于某种原因,我得到了最奇怪的结果:

    text    "con_gameMsgWindow0LineCount"   string
    hasher  {Fnv1a.Fnv1a32} Fnv1a.Fnv1a32
    bytes_encoded   {byte[0x0000001b]}  byte[]
    byte_hash   {byte[0x00000004]}  byte[]
    uint32  0x0a65c1a8  uint
    uint32_hex  "A65C1A8"   string
    uint32_dec  "174440872" string
    stringg "A8C1650A"  string
    expected_hex    "FC60C821"  string
    expected_dec    "4234201121"    string

我真的要把头撞到桌子上,因为我似乎无法弄清楚为什么它没有计算正确的哈希值(我使用的是https://github.com/jslicer/FNV-1a的修改版,可以更改基数和偏移量)

1 个答案:

答案 0 :(得分:2)

FNV1a哈希本身可以在C#代码中运行。但是,关于输入数据的处理,C#代码与Python代码在以下几点上有所不同:

  • C#代码不会在最后删除\r\n
  • C#代码不会转换为小写字母。
  • 在C#代码中未附加0字节。

此外,C#代码不使用文本con_gameMsgWindow0MsgTime,而是使用con_gameMsgWindow0LineCount

解决方案是在C#代码的ToHashFnv1a32方法的开头添加以下行:

text = text.TrimEnd('\r', '\n').ToLower() + "\0";

,当然,在两个代码中都必须使用相同数据进行测试。

注意:Python代码中使用的质数和偏移量基数与commonly used values不同。