Oracle의 STANDARD_HASH와 일치하도록 Python의 정수 해시
오라클에서 내 데이터는 'STANDARD_'에 정수를 전달하여 해시되었습니다.해시'는 다음과 같습니다.파이썬을 사용하여 동일한 해시 값을 얻으려면 어떻게 해야 합니까?
정수가 STANDARD_에 전달되면 Oracle이 생성됩니다.해시:
SELECT STANDARD_HASH(123, 'SHA256') FROM DUAL;
# A0740C0829EC3314E5318E1F060266479AA31F8BBBC1868DA42B9E608F52A09F
문자열이 전달될 때 Python이 됩니다.
import hashlib
hashlib.sha256(str.encode(str(123))).hexdigest().upper()
# A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3
# I want to modify this function to get the hash value above.
아마도 이 정보도 도움이 될 것입니다.Oracle 측에서는 아무것도 변경할 수 없지만, 변경할 수 있다면 열을 다음으로 변환할 수 있습니다.CHAR
현재의 Python 구현과 동일한 가치를 제공합니다.그 예는 다음과 같습니다.
STANDARD_에 문자열이 전달되면 Oracle이 생성됩니다.해시:
SELECT STANDARD_HASH('123', 'SHA256') FROM DUAL;
# A665A45920422F9D417E4867EFDC4FB8A04A1F3FFF1FA07E998E86F7F7A27AE3 (matches Python result)
단순히 파이썬에 정수를 전달하는 등 여러 번 시도했지만 문자열이 필요하다는 오류가 발생합니다.정수를 인코딩하는 방법도 찾아봤지만 진행되지 않았습니다.
Oracle은 자체 내부 형식으로 숫자를 나타냅니다. 이는 다음을 사용하여 확인할 수 있습니다.dump()
기능을 제공합니다.예.,
SELECT dump(123) FROM dual;
Typ=2 Len=3: 194,2,24
따라서 Python에서 숫자를 해시하고 Oracle에서와 동일한 결과를 얻으려면 Oracle이 내부에서 수행하는 것과 동일한 방식으로 Python 숫자를 바이트 집합으로 변환해야 합니다.
Oracle이 사용하는 내부 로직에 대한 좋은 분석은 여기에서 확인할 수 있습니다.음수를 종료하는 것과 관련된 하나의 사소한 누락이 정확합니다.또한 오라클 숫자를 바이트에서 디코딩하는 관점에서 작성됩니다.이 경우 Oracle 번호를 내부 바이트 형식으로 인코딩해야 합니다.그럼에도 불구하고, 저는 이 답을 만드는 데 광범위하게 사용했습니다.
아래 코드는 파이썬 함수를 보여줍니다.to_oracle_number()
이것은 오라클 데이터베이스가 계산하는 것과 동일한 숫자의 바이트 표현을 가진 정수 배열을 반환합니다.숫자(양, 음, 분수, 0 등)를 처리해야 합니다.
맨 아래에 있는 코드는 또한 이 함수를 호출하고 오라클 데이터베이스에서 계산된 것과 동일한 해시 값을 얻기 위해 결과를 해시하는 방법을 보여주는데, 이것이 당신의 질문의 핵심이라고 생각합니다.
참고: 이 함수는 변환할 숫자가 문자열로 전달되어 정밀도 손실을 방지할 것으로 예상합니다.
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())
산출량
Typ=2 Len=3: 194,2,24 [194, 2, 24] A0740C0829EC3314E5318E1F060266479AA31F8BBBC1868DA42B9E608F52A09F
경고: 스레드에 대한 원래 솔루션은 @Matthew McPeak에서 제공되며, 이에 대한 답은 보상을 받아야 합니다. 아래에는 제가 그의 알고리즘에 약간의 리팩터링을 추가한 약간 수정된 버전이 있습니다.
import math
import decimal
import hashlib
def to_oracle_number(nstr):
n = decimal.Decimal(nstr)
# compute exponent (base 100) and convert to Oracle byte along with sign
l_exp, l_len, l_abs_n = 0, 0, abs(n)
if l_abs_n != 0:
l_exp = math.floor(math.log(l_abs_n, 100)) + 65
l_exp = (l_exp ^ 127) if n < 0 else l_exp + 128
l_bytes = [l_exp]
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 += '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_chunks = ''
for i in range(0, int(len(l_mantissa) / 2)):
l_chunk = int(l_mantissa[i * 2:i * 2 + 2])
if n < 0:
l_chunk = 100 - l_chunk
l_chunk += 1
l_chunks = f"{l_chunks},l_chunk"
l_bytes.append(l_chunk)
l_len += 1
if n < 0 and l_len < 21:
# terminating negative numbers always end in byte 102 (do not know why)
l_chunks += ',102'
l_bytes.append(102)
l_len += 1
# bytes(l_bytes)l_computed_dump = f"Typ=2 Len={l_len}: {l_exp}{l_chunks}"
m = hashlib.sha256()
m.update(bytes(l_bytes))
return m.hexdigest().upper()
if __name__ == '__main__':
assert to_oracle_number('123') == "A0740C0829EC3314E5318E1F060266479AA31F8BBBC1868DA42B9E608F52A09F"
언급URL : https://stackoverflow.com/questions/55519820/hash-an-integer-in-python-to-match-oracles-standard-hash
'programing' 카테고리의 다른 글
Spring Boot 1.3.3 @EnableResourceServer 및 @EnableOAuth2So 동시에 (0) | 2023.07.22 |
---|---|
Spring-Boot: 여러 요청 동시 처리 (0) | 2023.07.22 |
Spring boot 응용 프로그램의 사용자 지정 오류 페이지로 리디렉션하는 중 오류 발생 (0) | 2023.07.22 |
Oracle DELETE 성능 향상 전략 (0) | 2023.07.22 |
웹 앱을 Spring Boot 2.4로 업그레이드한 후 잘못된 StateException (0) | 2023.07.22 |