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 등을 사용할 수 있다.