(JAVA) SHA-256 암호화

lgw2236·2022년 12월 27일
0

Java

목록 보기
4/8

이번에 암호화 방식을 SHA-256으로 바꿔야 하는 개발건이 생겨 해당 암호화에 대해 공부한 것을 정리 해보았다...

SHA-256 암호화란?

SHA -256은 SHA(Secure Hash Algorithm) 알고리즘의 한 종류로써 256비트로 구성되며 64자리 문자열을 반환한다. SHA -256은 단방향 암호화 방식이기 때문에 복호화가 불가능 하다는 것이 큰 특징이며, 복호화를 하지 않아도 되기 때문에 속도가 빠른 장점이 있다.

자바에서 SHA-256을 사용하기 위해선 java.security 에서 제공해주는 MessageDigest를 import 하면된다.

예시코드

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SHA256Util {
	
	  public String encrypt(String text) throws NoSuchAlgorithmException {
		  
	        MessageDigest md = MessageDigest.getInstance("SHA-256");
	        try {
				md.update(text.getBytes("UTF-8"));
			} catch (UnsupportedEncodingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	        return bytesToHex(md.digest());
	        
	    }
	    private String bytesToHex(byte[] bytes) {
	    	
	        StringBuilder builder = new StringBuilder();
	        for (byte b : bytes) {
	            builder.append(String.format("%02x", b));	            
	        }
	        return builder.toString();
	    }

	}

레인보우 테이블 방지

레인보우 테이블이란?
해시 함수(MD5, SHA-1, SHA-2 등)을 사용하여 만들어낼 수 있는 값들을 왕창 저장한 표인데
해당 데이터로 매칭하여 해킹을 하는 사례들이 있어 이를 방지하기 위해 코드에
일정 문자열을 추가하는 "salt" 방식이 생겼다.

salt란?

앞서 말한것과 같이 기존의 원본 문자열에 랜덤 문자열을 추가하여 SHA-256 방식으로
변환한 것을 말한다.
원본 문자열만으로 암호화한 데이터는 레인보우 테이블로 인해 해킹 당할 위험이 제로는 아니기 때문에 이에 랜덤 문자열을 추가하여 암호화해 랜덤 문자열(salt)과 기존문자열 + 랜덤문자열을 암호화한 full String 을 사용하여 이중으로 validation을 걸수도 있어 더욱 안전하다 볼 수 있겠다..
이 때 랜덤으로 생성한 salt의 경우에는 DB에 필드값으로 저장해 놓는것이 관리자입장에서 추후 비밀번호나 다른 데이터를 매칭할때 유용하다.
(애초에 랜덤 문자열이기 때문에 salt를 저장해놓지 않으면 DB에 있는 데이터와 로그인이나 다른 입력 INPUT을 할 떄 데이터 매칭시키기가 거의 불가능하다.)

salt 사용 코드 예시

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class SHA256UtilWithSalt {

    public String getEncryptPassword(String password, byte[] salt) {

        String encryptPassword = null;
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(salt);
            byte[] bytes = md.digest(password.getBytes());
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < bytes.length; i++) {
                sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
            }
            encryptPassword = sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return encryptPassword;
    }

    private byte[] getSalt() throws NoSuchAlgorithmException {
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[16];
        random.nextBytes(salt);
        return salt;
    }

test코드 예시(with salt)


import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import com.skt.tx.util.SHA256Util;

public class testbbb {
	public static void main(String[] args) throws Exception {
			  // same salt should be passed
		    byte[] salt = getSalt();
		    String password = getSecurePassword("Password", salt);
		    String password2 = getSecurePassword("password", salt);
		 
		    System.out.println(" Password  -> " + password);
		    System.out.println(" Password 2 -> " + password2);
		    if (password1.equals(password2)) {
		        System.out.println("passwords are equal");
		        	        
		}
		
	}
	    public static String getSecurePassword(String password, byte[] salt) {

	        String generatedPassword = null;
	        try {
	            MessageDigest md = MessageDigest.getInstance("SHA-256");
	            md.update(salt);
	            byte[] bytes = md.digest(password.getBytes());
	            StringBuilder sb = new StringBuilder();
	            for (int i = 0; i < bytes.length; i++) {
	                sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
	            }
	            generatedPassword = sb.toString();
	        } catch (NoSuchAlgorithmException e) {
	            e.printStackTrace();
	        }
	        return generatedPassword;
	    }

	    private static byte[] getSalt() throws NoSuchAlgorithmException {
	        SecureRandom random = new SecureRandom();
	        byte[] salt = new byte[16];
	        random.nextBytes(salt);
	        return salt;
	    }
	    

}

결과

 Password  -> 5c2c286570154e86d7efbb07ad56548e87db4f426332a076d94d1cc4426d80ca
 Password 2 -> 11d4f3654f98ad1d9ce3038a1e338c97e0ec4db8ef7152dd5bed799718350d21
 대소문자도 다른문자로 구분하는걸 볼수있다. ( P != p )
profile
어제보다 오늘 더

0개의 댓글