해시함수란 임의의 길이를 가진 데이터를 고정된 길이의 데이터로 매핑하는 함수를 말한다.
원본 데이터의 정보를 상실하여 생성된 해시값은 복원할 수 없는 일방향성을 가지며,
현재 암호화 알고리즘 외에도 다양한 분야에서 빼놓을 수 없는 기술이다.
다양한 알고리즘 중, 일반적으로 많이 사용하는 알고리즘은 MD5, SHA가 있다.
MD5(Message-Digest algorithm 5)는 128비트의 다소 작은 크기의 해시값 출력과
알고리즘 자체의 결함도 알려져있어 최근에는 네트워크로 전송되는 파일의
무결성 검증 등에서만 활용된다.
파이썬의 Pycryptodome 모듈에서 제공하는 MD5,
파이썬 자체에서 제공하는 hashlib 모듈의 md5를 임포트하여 사용하면 된다.
SHA(Secure Hash Algorithm)은 미국 NSA가 만든 해시함수이며
SHA-0, SHA-1, SHA-2, SHA-3 으로 발전해 왔다.
파일의 무결성이나 인덱싱을 위해 SHA-1 알고리즘이 활용되었고,
패스워드 암호화나 블록체인 등에서는 SHA-2 시리즈 중 SHA-256이 광범위하게 사용된다.
SHA-256은 256비트 크기의 해시값을, SHA-512는 512비트 크기의 해시값을 출력한다.
이론적으로 해시충돌의 가능성이 있다고 알려져 있으나 그 가능성은 거의 0에 가깝다.
해시충돌(Hash Collision)
해시값은 두 개의 다른 입력값에 대해 특정 확률로 동일한 해시값이 나올 수 있다.
이와 같은 상황을 해시 충돌이라고 부르며, 여기서 말하는 특정 확률이란 매우 작은
값이므로 통계적으로 큰 의미가 없다고 해도 무방하다.
DBMS에서 검색을 위한 인덱스로 해시가 활용된다.
검색하고자하는 값을 해시함수에 입력하여 나오는 값과 일치하는 인덱스를 찾고,
해당 레코드 위치를 찾아가는 기법이다.
해시의 특성으로 인해 입력한 값과 동일한 값을 검색하는 동등 비교 검색에서는
탁월한 성능을 보이나, 범위 검색에서는 매우 비효율적인 방법이다.
해시는 사용자 계정의 비밀번호를 암호화하는 방법으로 많이 활용된다.
리눅스 계열의 OS는 비밀번호를 MD5나 SHA-256 해시값으로 변환하여 보관한다.
해시값은 어떤 데이터의 지문값으로도 불린다. 2개의 데이터가 존재할 때,
각각의 데이터에 대한 해시값이 일치하면 이 2개의 데이터는 완전히 동일한 데이터임을
보장할 수 있다. 어떤 정보의 위조나 변조가 이루어지면, 이 정보의 해시값은
원본 데이터의 해시값과 완전히 다른 값이 될 것이다.
블록체인 기술에서 매우 광범위하게 활용되고 있으며, 블록체인의 각각의 블록 주소는
공개키의 해시값으로 이루어져 있고, 이러한 블록들을 연결하는 데 활용되는 기술이
해시이다. 또한 비트코인이 수행하는 작업증명이라는 과정은 해시캐시라 부르는
해시 문제풀이를 수행하는 과정이다.
2개의 파일 내용의 일치 여부를 확인하는 데 해시를 사용할 수 있다.
특히 데이터의 크기가 매우 큰 파일의 경우 해시를 통해 쉽게 비교를 할 수 있다.
컴퓨터의 메모리를 절약하기 위해 파일 내용을 한꺼번에 읽어 이에 대한 SHA256 해시를
구하는 대신, 256KB 크기로 정보를 읽어 해시를 업데이트하는 방법으로 진행한다.
from hashlib import sha256 as SHA
SIZE = 1024*256 # 256KB 정의
def getFileHash(filename) :
sha = SHA()
h = open(filename, 'rb')
content = h.read(SIZE) # 파일에서 256KB만큼 읽어온다
while content:
sha.update(content) # 읽은 정보만큼 해시할 데이터 갱신
content = h.read(SIZE) # 파일에서 그 다음 256KB 읽음
h.close()
hashval = sha.digest() # 최종 해시값 계산산
return hashval
def hashCheck(file1, file2):
hashval1 = getFileHash(file1)
hashval2 = getFileHash(file2)
if hashval1 == hashval2:
print('Two Files are Same')
else:
print("Two Files are Different")
def main():
file1 = 'plain.txt'
file2 = 'plain.txt.enc.dec'
hashCheck(file1, file2)
main()
위 코드를 통해 어떠한 크기의 파일이어도 두 개의 파일에 대한 무결성 체크를 완벽하게
해낼 수가 있다.
패스워드 Salting 이란, 사용자의 패스워드를 해시하기 전에 랜덤한 값(Salt)을
추가하여 보안을 강화하는 기법이다.
각각의 사용자에게 고유하고 랜덤한 값인 Salt를 생성한 후, 사용자가 입력한 패스워드에
salt를 추가하고, 그 값을 해시 알고리즘을 사용하여 해싱한다.
데이터베이스에는 Salt + 해시값
형태로 저장하여 사용자가 로그인할 때,
입력한 패스워드에 저장된 salt를 추가하여 해시값을 다시 계산한 후
그 결과가 저장된 해시값과 일치할 경우 인증에 성공한다.
이와 같은 기법을 사용하여 레인보우 테이블(사전에 계산된 해시값과 대응되는 패스워드
리스트)을 이용한 공격을 방어하고, 사용자마자 해시값이 달라지기 때문에, 패스워드를
중복하여 사용하는 사용자라도 서로 다른 salt를 사용하여 보안을 강화한다.