java/jca

MessageDigest 클래스를 사용한 해시값 생성

tmxhsk99 2019. 6. 11. 14:34
package jce;

import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MessageDigestExample {
	
	public static void main(String[] args) throws NoSuchAlgorithmException {
		Charset charset = Charset.forName("UTF-8");
		String plainText = "오";
		MessageDigest md = MessageDigest.getInstance("SHA-256");
		md.update(plainText.getBytes());
		byte[] hash = md.digest();
		System.out.println(SecureRandom.bytesToHexString(hash));
		
	}

	
}

 

결과 

B9C663CA8C1622B3AC665E093E039C9679CE2D745BC6C5AD25480191FC2F05C1

128비트 

64개의 16진수로 표현가능 


체크섬

- 일반적인 해시함수는 데이터의 체크섬을 생성하기 위해서 사용한다.

  아파치톰캣에서서 파일의 유효성을 체크하기 위해 MD5같은 체크섬 정보를 제공한다 

  파일 정보를 체크해 보자 

 

package jce;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class ChecksumExample {
	public static void main(String[] args) throws NoSuchAlgorithmException, FileNotFoundException {
		File file = new File("D:"+File.separator+"install"+File.separator+"apache-tomcat-8.5.42.zip");
		String sha512 = "1c00f5fcbfc3d9ce1125cd698fc3fc8b4a61b2782b8753033ceb19da04b64d1d64a42e083ca8d7433a8fdcd2bf12ac5d98405c8fdfa369b27d925b5c4f9ccc4a";
		MessageDigest md = MessageDigest.getInstance("sha-512");
		InputStream in = new BufferedInputStream(new FileInputStream(file));
		
		try {
			byte[] buffer = new byte[1024];
			int read = -1;
			while((read = in.read(buffer)) != -1) {
				md.update(buffer,0,read);
			}
		} catch (Exception e) {
			
		}finally {
			try { in.close();} catch (IOException e2) {			}
		}
		byte[] hash = md.digest();
		System.out.println("SHA-512 방식의 pache-tomcat-8.5.42.zip 파일의 해시값  : " + sha512);
		System.out.println("실제 pache-tomcat-8.5.42.zip 파일에 SHA-512 해시 알고리즘을 취한 값  : " + SecureRandom.bytesToHexString(hash));
		System.out.println("해시값 비교  : "+sha512.equalsIgnoreCase(SecureRandom.bytesToHexString(hash)));
	}
}

MessageDigestInputStream을 이용하면 더 짧아진다. 

package jce;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.bouncycastle.crypto.io.DigestInputStream;

public class Checksum2Example {
	public static void main(String[] args) throws NoSuchAlgorithmException, FileNotFoundException {
		File file = new File("D:"+File.separator+"install"+File.separator+"apache-tomcat-8.5.42.zip");
		String sha512 = "1c00f5fcbfc3d9ce1125cd698fc3fc8b4a61b2782b8753033ceb19da04b64d1d64a42e083ca8d7433a8fdcd2bf12ac5d98405c8fdfa369b27d925b5c4f9ccc4a";
		MessageDigest md = MessageDigest.getInstance("sha-512");
		InputStream in = new java.security.DigestInputStream(new BufferedInputStream(new FileInputStream(file)), md);
		
		try {
			while(in.read() != -1);
			
		} catch (Exception e) {
			
		}finally {
			try { in.close();} catch (IOException e2) {			}
		}
		byte[] hash = md.digest();
		System.out.println("SHA-512 방식의 pache-tomcat-8.5.42.zip 파일의 해시값  : " + sha512);
		System.out.println("실제 pache-tomcat-8.5.42.zip 파일에 SHA-512 해시 알고리즘을 취한 값  : " + SecureRandom.bytesToHexString(hash));
		System.out.println("해시값 비교  : "+sha512.equalsIgnoreCase(SecureRandom.bytesToHexString(hash)));
		
	}
}

 

패스워드 저장

해시 함수는 단방향 함수여서 해시값에서 원본 복원이 불가능 

패스워드 저장을 위해 해시 함수를 사용하기도 한다. 

SHA-1 알고리즘을 이용한 패스워드 함수 예제 

보통 MySQL에서  패스워드를 저장하기 위해서 사용하는 방법으로 SHA-1 해시 함수를 두번 호출하고 생성된 해시 값을 16진수의 문자열로 만든다. 

package jce;

import java.security.MessageDigest;


public class MySqlPasswordEx {
	public static void main(String[] args) {
		String password = "helloworld";
		String digest = password(password);
		System.out.println("Mysql Password = "+digest);
				
	}
	
	/**
	 * 입력한 데이터를 SHA-1  알고리즘으로 처리하여 해시값을 계산한다.
	 * @param input 입력 데이터(<code>null</code>이면 안 된다.)
	 * @return 해시값 
	 * 
	 */
	public static byte[] getHash(byte[] input){
		try {
			MessageDigest md = MessageDigest.getInstance("SHA-1");
			return md.digest(input);
		} catch (Exception e) {
			throw new RuntimeException("SHA1"+"Algorithm Not Found",e);
		}
	}
	

	/**
	 * MySQL의  PASSWORD() 함수 
	 *
	 *@param input 입력 데이터
	 *@return 
	 */
	public static String password(byte[] input){
		byte[] digest = null;
		//Stage 1
		digest = getHash(input);
		//Stage 2 
		digest = getHash(digest);
		StringBuilder sb = new StringBuilder(1 + digest.length);
		sb.append("*");
		sb.append(SecureRandom.bytesToHexString(digest).toUpperCase());
		return sb.toString();
		
	}
	/**
	 * @author dream
	 * @param input
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	public static String password(String input){
		
		if(input == null){
			return null;
		}
		return password(input.getBytes());
		
	}
}

 

사전 공격등 위험이 존재하므로 Salt 와 반복횟수를 사용하는것이 안전하다. 

점더 안전한 방법은 PBKDF2,bcrypt,scrypt 등을 사용할 수 있다.