본문 바로가기

회고록(TIL&WIL)

TIL 2023.06.26 HMAC(keyed-Hash Message Authentication Code)

HMAC (keyed-Hash Message Authentication Code)

데이터를 보낼 때 데이터와 함께 해당 데이터를 해싱처리한 HMAC의 값을 함께 보냄으로써 수신자의 입장에서 해당 데이터가 위변조가 되었는지 안되었는지 파악할 수 있게 해준다.

 

이를 이용하려면 우선 요청자, 수신자 간의 약속이 2가지 필요하다.

SecretKey 와 Algorithm 두가지를 서로 공유하고 있어야한다.

데이터를 같은 방식으로 암호화를 하여야 HMAC 값이 동일하게 나오며 같음 여부에 따라 위변조를 파악 할 수 있기 때문

 

import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class HmacEncrypt {

    private static final String SECRETKEY = "TEST";
    private static final String WRONGKEY = "TEXT";
    private static final String ALGORITHMS = "HmacSHA512";
	
    public static String encode(String secretKey, String algorithms, String msg) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
        Mac haser = Mac.getInstance(ALGORITHMS);
        haser.init(new SecretKeySpec(SECRETKEY.getBytes("utf-8"), ALGORITHMS));
        byte[] hash = haser.doFinal(msg.getBytes());
        return Base64.encodeBase64String(hash);

    }

}

아래 결과 처럼 받은 데이터를 encoding한 것과 받은 hmac의 값이 동일 할 경우에만 위/변조 되어있지 않다는 것을 확인할 수 있으며 예시의 경우는 짧은 문자열인지라 굳이 왜하는가 생각할 수 있지만 내용이 엄청나게 많은 XML 파일의 내용이라던가 깊이가 매우 깊은 JSON 데이터등이라고 한다면 이를 일일히 확인할 수 없다. 그렇기 때문에 서로 신뢰할 수 있는 통신임을 확인하기 위해서 이를 사용하는 것이다.

package com.example.demo.controller;

import com.example.demo.encrypt.HmacEncrypt;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

@RestController
public class HomeController {

    @GetMapping("/test")
    public String test() throws InvalidKeyException, NoSuchAlgorithmException {

        String msg = "Hello, HMAC!";
        String algorithms = "HmacSHA512";
        String secretKey = "TEST";
        String wrongKey = "TEXT";

        String hmac = HmacEncrypt.encode(secretKey, algorithms, msg);
        String hmac2 = HmacEncrypt.encode(secretKey, algorithms, msg);
        String forseryHmac = HmacEncrypt.encode(secretKey, algorithms, msg + "123");
        String wrongKeyHmac = HmacEncrypt.encode(wrongKey, algorithms, msg);
        return msg + "<br>" + hmac + "<br>" + hmac2 + "<br>" +  forseryHmac + "<br>" + wrongKeyHmac;
    }

}

*위의 코드는 Spring boot 환경에서 thymeleaf를 이용.

// 출력 결과
hmac  = 5Y++//KRhZHo+zZ/iTyjAefvxYlAhDoLG12+cByv+D/44Bx6J0/c5M0PycU26Hxabxyci8JkSABMe+jJ3FzlPA==
hmac2 = 5Y++//KRhZHo+zZ/iTyjAefvxYlAhDoLG12+cByv+D/44Bx6J0/c5M0PycU26Hxabxyci8JkSABMe+jJ3FzlPA==
forseryHmac = oMvE4EKMxaxe47ktc4cvAbzmWyciE2vCBV5G/Ju1eL0ZqNx4tgm3KNLfZPU3Rgv0Mse+npSB5fXSzbBQh9WRkQ==
wrongKeyHmac = vRtm5BEPNZNMz0DGyKkHWiWaZkmqkJOi/dfJB512/JPKM6cbeFwZQ7n54WLhJ2YNfKCa3ClqgBIdrJOm2AK8Ig==