삶 가운데 남긴 기록 AACII.TISTORY.COM
Message Digest 메시지 다이제스트 본문
자바에서 메시지 다이제스트 값을 계산하려면 MessageDigest 클래스를 사용합니다.
메시지 다이제스트는 소스가 되는 이진(byte)값에 대한 해시 값을 구하는 것입니다.
해시 값도 이진(byte) 값이어서 16진수 String으로 변환해서 읽기 쉽게 변환해서 사용합니다.
원본 소스가 같으면 같은 해시 값이 나오고 원본 소스가 달라지면 다른 해시 값이 나오는 특성 때문에 전자 서명이나 파일의 무결성 검증(위변조 여부 감지) 등에 사용됩니다.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class FileHashCalculator {
//파일을 읽어서 해시 계산후 String으로 리턴
public String getHash(String filePath, String algorithm) {
StringBuilder hashString = new StringBuilder();
File file = new File(filePath);
try {
MessageDigest digest = MessageDigest.getInstance(algorithm);
try(FileInputStream fis = new FileInputStream(file)){
byte[] buffer = new byte[1024];
int bytesRead;
//파일 데이터를 읽으면서 해시 계산
while((bytesRead = fis.read(buffer)) != -1) {
digest.update(buffer, 0, bytesRead);
}
byte[] encodedHash = digest.digest();
for (byte b : encodedHash) {
hashString.append(String.format("%02x", b));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return hashString.toString();
}
public boolean createHashFile(String fileName) {
String path = fileName;
String hashValue = getHash(path,"SHA-256");
path = fileName+".hash";
try (BufferedWriter writer = new BufferedWriter(new FileWriter(path))) {
writer.write(hashValue);
}catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean createFile(String fileName) {
String path = fileName;
String contents = "example text";
try (BufferedWriter writer = new BufferedWriter(new FileWriter(path))) {
writer.write(contents);
}catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean verifyHash(String fileName, String hashFileName) {
boolean isEqual = false;
String filePath1 = fileName;
String filePath2 = hashFileName;
//fileName 내용을 읽어서 해시값을 구한다.
String hash1 = getHash(filePath1, "SHA-256");
//hashFileName의 내용을 읽는다.
String hash2 = readFile(filePath2);
//두 해시값을 비교한다.
if(hash1.equals(hash2)) {
isEqual = true;
}else {
isEqual = false;
}
return isEqual;
}
public String readFile(String filePath) {
String savedHash = filePath;
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
savedHash = br.readLine();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return savedHash;
}
public static void main(String[] args) {
try {
String filePath1 = "hashTest.txt"; // 해시 값을 구할 원본 소스 파일
createFile(filePath1); //원본파일 생성
String filePath2 = "hashTest.txt.hash"; // 해시 값이 저장된 파일
//원본 파일에 대한 해시값을 저장할 파일 생성
createHashFile(filePath1);
//원본 파일에 대한 해시 값과 저장된 해시 파일과 비교
boolean isEqual = verifyHash(filePath1, filePath2);
if(isEqual){
System.out.println("Equal");
}
} catch (NoSuchAlgorithmException e) {
System.err.println("Invalid algorithm: " + e.getMessage());
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
}
}
}
주의할 점
이진 파일이나 텍스트 파일에 모두 적용할 수 있지만 텍스트 파일의 경우 인코딩 방식이나 운영 체제별 줄바꿈 방식에 따라 같은 파일이라도 해시 값이 달라질 수 있습니다.
- 문자 인코딩 차이:
- 텍스트 파일의 인코딩이 다르면 동일한 내용을 가진 파일이라도 해시 값이 달라질 수 있습니다.
- 그러나 위 메서드는 파일의 바이트 데이터를 그대로 읽으므로, 인코딩과는 무관하게 작동합니다.
- 운영 체제별 줄바꿈:
- Windows는 \r\n, UNIX/Linux는 \n을 줄바꿈 문자로 사용합니다.
- 운영 체제 간 파일 이동 시 줄바꿈 문자가 변경되면 파일의 해시 값도 달라질 수 있습니다.
- 파일 내용이 동일하더라도 줄바꿈 문자의 차이로 해시 값이 달라질 수 있다는 점을 염두에 두세요.
728x90
'DEV&OPS > Java' 카테고리의 다른 글
[SWT/JFace] Display 클래스, Shell 클래스, 메시지 박스 예제 (81) | 2024.11.27 |
---|---|
[SWT/JFace] 이클립스 플러그인 개발 환경 설정 (4) | 2024.11.27 |
안드로이드 이클립스 dx.jar was not loaded from the SDK folder! 에러 (0) | 2024.05.10 |
Unsupported class version number [52.0] (maximum 51.0, Java 1.7) (2) | 2024.05.10 |
이클립스 웹 프로젝트 이름 변경 (0) | 2024.05.10 |