hashing 해싱 해쉬

https://arikong.tistory.com/15

 

해쉬 알고리즘을 이용해서 일정한 길이의 암호화된 문자열을 생성하는 일을 Hashing이라고 하고

그 Hashing 이후의 값을 Hash 값

Hash 값을 만들어내는 함수를 Hash 함수라고 합니다.

원본으로 되돌릴 수 없다는 특징이 있습니다. (복호화 불가)

 

해싱

임의의 길이 데이터를 입력받아 고정된 길이의 출력값(해시값 또는 다이제스트)으로 변환하는 과정.

더 다양한 해싱에 관한 정보는 여기 (https://gong-story.tistory.com/27)

메시지 다이제스트 (Message Digest)

해싱 과정을 거쳐 생성된 결과물로, 원본 메시지를 대표하는 짧고 고유한 값

(큰 데이터가 짧고 '날씬해진다'고 하여 메시지 '다이제스트(요약본)'라고 불림.)

  • 해싱은 '방법', 메시지 다이제스트는 '결과물'입니다.
  • '해싱 알고리즘을 통해 메시지 다이제스트를 생성한다'고 표현할 수 있습니다. 

"Hello World"라는 메시지를 SHA-256으로 해싱하면, 항상 동일한 256비트(64자)의 고정된 길이 다이제스트가 나옵니다. 이 값이 바로 메시지 다이제스트입니다.

자바(Java)에서는 MessageDigest 클래스를 사용하여 이러한 해싱 및 다이제스트 생성을 구현합니다. 

 

HMAC(Hash based Message Authentication Code)

 HMAC에서 MAC는 메세지를 주는 사람과 받는 사람 사이에 그 메세지가 변형되지는 않았는지 확인하는 방법(변조 여부)으로 앞에 "H"가 붙으면 Hash 알고리즘을 이용한다는 뜻입니다. 

 

어떻게 변형이 안 됐는지를 확인하느냐?

송신자와 수신자는 사전에 비밀키를 공유합니다.

그리고 비밀키와 전달하고자하는 원본 메세지를 사용하여 해싱을 진행합니다. 그렇게 md(메시지 다이제스트) 값이 생성이 됩니다.

송신자가 통신을 통해 md값과 원본 메세지를 전달하면,

수신자는 비밀키를 사용하여 원본메세지를 스스로 해싱해봅니다.

해싱하여 나온 md값이 서로 동일하면 메세지의 변형이 없는 것임이 입증됩니다. (인증 성공)

 

이렇게 키를 공유하는 것을 대칭키 암호화라고 합니다.

 

더 자세한 hmac에 대한 내용은 이 블로그에 (https://berom.tistory.com/115)


1. hashing을 사용하려면 라이브러리가 필요합니다. java, kotlin의 경우에는 crypto를 임포트 해주면 됩니다.

import javax.crypto.Mac

 

2. 암호화 유틸의 엔진을 생성해줍니다.

val mac = Mac.getInstance("HmacSHA1")

이 때 인스턴스에 들어갈 알고리즘은 여기(https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Mac)에서 확인 가능

 

3. mac을 초기화 할 때 필요한 keySpec을 만들어준다.

이 때 서로 공유 받은 비밀키를 사용한다.

import javax.crypto.spec.SecretKeySpec

val keySpec = SecretKeySpec(비밀키.toByteArray(Charsets.UTF-8), "HmacSHA1")
mac.init(keySpec)

UTF-8의 평문을 Byte로 전환해서 전달하고,  알고리즘도 같이 전달한 뒤에 init한다.

KeySpec에 대해서는 다음과 같이 설명되어 있다.

// Constructs a secret key from the given byte array.

public SecretKey(byte[] key, String algorithm) {
 key나 algorithm이 null일 경우 IllegalArgumentException("Missing argument")
 key의 length가 0일 경우 IllegalArgumentException("Empty key")
}

 

4. 키 업데이트하기.

이제 키가 만들어졌으니, 키를 사용하여 원본 메세지를 키에 업데이트 해줍시다.

mac.update(message.toByteArray(Charsets.UTF-8))

mac이 바이트 값만 받기 때문에, UTF-8로 설정된 원본 메세지를 byte로 변경해주는 것입니다.

 

>>> 이 때 원본메세지를 더 복잡하게 만들기 위해서 여러가지 값이 원본메세지에 더해지기도 합니다.

 

5. doFinal을 통하여 마무리하기

val hmd = Base64.getEncoder().encodeToString(mac.doFinal())

 

md값은 binary, hex, base64로 최종 인코딩 됩니다.

binary : 2진수 / hex : 16진수 / base64 : 64진수