在Python中哈希一个整数以匹配Oracle的STANDARD_HASH

Bob*_*bby 14 python oracle hash

在Oracle中,我的数据已通过将整数传递到“ STANDARD_HASH”中进行散列,如下所示。如何使用Python获得相同的哈希值?

将整数传递给STANDARD_HASH时在Oracle中产生结果:

SELECT STANDARD_HASH(123, 'SHA256') FROM DUAL;
# A0740C0829EC3314E5318E1F060266479AA31F8BBBC1868DA42B9E608F52A09F
Run Code Online (Sandbox Code Playgroud)

传入字符串时在Python中产生的结果:

import hashlib

hashlib.sha256(str.encode(str(123))).hexdigest().upper()
# A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3
# I want to modify this function to get the hash value above.
Run Code Online (Sandbox Code Playgroud)

也许这些信息也会有所帮助。我无法在Oracle方面进行任何更改,但如果可以的话,我会将列转换为,CHAR并且其值将与当前的Python实现相同。下面是一个示例。

将字符串传递给STANDARD_HASH时在Oracle中产生结果:

SELECT STANDARD_HASH('123', 'SHA256') FROM DUAL;
# A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3 (matches Python result)
Run Code Online (Sandbox Code Playgroud)

我做了几次尝试,比如简单地将整数传递给Python,但这会导致错误,要求输入字符串。我也一直在寻找一种编码整数的方法,但是没有取得任何进展。

Mat*_*eak 10

Oracle用自己的内部格式表示数字,可以使用dump()Oracle中的函数看到它。例如,

SELECT dump(123) FROM dual;
Run Code Online (Sandbox Code Playgroud)
Typ=2 Len=3: 194,2,24
Run Code Online (Sandbox Code Playgroud)

因此,要在Python中对数字进行散列并获得与Oracle中相同的结果,您需要像在Oracle内部一样将Python数字转换为一组字节。

这里可以找到对Oracle使用的内部逻辑的良好分析。这是正确的,与终止负数有关的一个小遗漏。同样,它是从从字节中解码 Oracle号的角度编写的。在我们的情况下,我们需要将Oracle数字编码为其内部字节格式。不过,我在形成这个答案时广泛使用了它。

下面的代码显示了Python函数,to_oracle_number()该函数将返回一个整数数组,该整数数组具有与Oracle数据库所计算的数字相同的字节表示形式。它应该处理任何数字(正数,负数,小数,零等)。

最底部的代码还显示了如何调用此函数并对其结果进行哈希处理以获得与在Oracle数据库中计算的哈希值相同的哈希值,我相信这是您问题的核心。

注意:该函数希望将要转换的数字作为字符串传递,以避免精度损失。

import math
import decimal
import hashlib

def to_oracle_number( nstr ):
  # define number n that we want to convert
  n = decimal.Decimal(nstr)

  # compute exponent (base 100) and convert to Oracle byte along with sign
  #print (abs(n))
  l_exp = 0
  l_len = 0

  l_abs_n = abs(n)


  if l_abs_n != 0:
    l_exp = math.floor(math.log(l_abs_n,100))
    # Oracle adds 1 to all bytes when encoding
    l_exp = l_exp + 1
    # Oracle adds 64 to exponent whe encoding
    l_exp = l_exp + 64

  if n < 0:
    # take 1's complement of exponent so far (bitwise xor)
    l_exp = (l_exp ^ 127)

  if n >= 0:
    # add sign bit.  zero is considered positive.
    l_exp = l_exp + 128

  l_bytes = []
  l_bytes.append(l_exp)

  l_len = l_len + 1   # exponent and sign take 1 byte

  l_whole_part = str(int(l_abs_n))
  # make sure there is an even number of digits in the whole part
  if len(l_whole_part) % 2 == 1:
    l_whole_part = '0' + l_whole_part

  # get the fractional digits, so if 0.01234, just 01234
  l_frac_part = str(l_abs_n - int(l_abs_n))[2:]
  # make sure there is an even number of digits in the fractional part
  if len(l_frac_part) % 2 == 1:
    l_frac_part = l_frac_part + '0'

  l_mantissa = l_whole_part + l_frac_part

  # chop off leading 00 pairs
  while l_mantissa[0:2] == '00':
    l_mantissa = l_mantissa[2:]

  # chop off trailing 00 pairs
  while l_mantissa[-2:] == '00':
    l_mantissa = l_mantissa[:-2]

  # compute number of 2-character chunks
  l_chunk_count = int(len(l_mantissa) / 2)

  l_chunks = '';

  for i in range(0, l_chunk_count):
    l_chunk = int(l_mantissa[i*2:i*2+2])
    if n < 0:
      # for negative numbers, we subtract from 100
      l_chunk = 100-l_chunk

    # Oracle adds 1 to all bytes
    l_chunk = l_chunk + 1

    # Add the chunk to our answer
    l_chunks = l_chunks + ',' + str(l_chunk)
    l_bytes.append(l_chunk)
    l_len = l_len + 1   # we have computed one more byte
    #print (str(i) + ':' + str(l_chunk))

  if n < 0 and l_len < 21:
    # terminating negative numbers always end in byte 102 (do not know why)
    l_chunks = l_chunks + ',102'
    l_bytes.append(102)
    l_len = l_len + 1

  l_computed_dump = 'Typ=2 Len=' + str(l_len) + ': ' + str(l_exp) + l_chunks
  print  (l_computed_dump)
  print  (l_bytes)

  return l_bytes


# test it

m = hashlib.sha256()
b = bytes(to_oracle_number('123'))  # pass a string so no precision errors
m.update(b)
print(m.hexdigest().upper())
Run Code Online (Sandbox Code Playgroud)

输出值

Typ=2 Len=3: 194,2,24
[194, 2, 24]
A0740C0829EC3314E5318E1F060266479AA31F8BBBC1868DA42B9E608F52A09F
Run Code Online (Sandbox Code Playgroud)

  • 好吧,不。那是问题,不是吗?您将需要Python用来实现Oracle用于生成“ NUMBER”个值的字节表示形式的任何逻辑。关于此有一些信息。例如:https://amitzil.wordpress.com/2015/03/24/how-are-numbers-saved-in-oracle/。但是我不确定尝试实现这样的事情是否明智,因为下次升级Oracle时它可能会改变(即使您非常谨慎,甚至可以使逻辑100%正确地开始)。 (2认同)