데이터의 무결성을 검증하는 가장 기본적인 방법입니다.
전송된 데이터가 올바른지 확인하는 간단한 방법입니다.
public class ChecksumExample {
public static int calculateChecksum(String input) {
int checksum = 0;
for (char c : input.toCharArray()) {
checksum += c;
}
return checksum % 256; // 8비트 체크섬
}
public static void main(String[] args) {
String message = "Hello, World!";
int checksum = calculateChecksum(message);
System.out.println("Message: " + message);
System.out.println("Checksum: " + checksum);
}
}
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HashExample {
public static String calculateSHA256(String input) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(input.getBytes());
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
해시(Hash)의 주요 특징과 각각의 의미, 활용 사례에 대해 자세히 설명해드리겠습니다.
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class PasswordHasher {
/**
* 문자열을 SHA-256으로 해싱하고 16진수 문자열로 반환
* @param input 해싱할 문자열
* @return 16진수 형태의 해시값
*/
public static String sha256Hash(String input) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// 입력 문자열을 바이트 배열로 변환하여 해싱
byte[] hash = digest.digest(input.getBytes());
// 바이트 배열을 16진수 문자열로 변환
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
public static void main(String[] args) {
try {
String password = "myPassword123";
String hashedPassword = sha256Hash(password);
System.out.println("Original: " + password);
System.out.println("Hashed: " + hashedPassword);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
String password = "myPassword123";
String hashedPassword = PasswordHasher.sha256Hash(password);
이 구현은 기본적인 해싱만 수행하며, 실제 패스워드 저장 시에는 솔트(salt)를 추가하고 더 강력한 해싱 알고리즘(예: PBKDF2, BCrypt)을 사용하는 것이 좋습니다.
보안이 중요한 프로덕션 환경에서는 이전에 보여드린 PBKDF2 구현을 사용하는 것을 권장합니다.
입력 데이터의 크기와 관계없이 항상 동일한 길이의 해시값 생성 합니다.
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Base64;
public class PasswordHasher {
private static final int SALT_LENGTH = 32; // 솔트 길이 (바이트)
private static final int HASH_LENGTH = 256; // 해시 길이 (비트)
private static final int ITERATIONS = 100000; // 반복 횟수
private static final String ALGORITHM = "PBKDF2WithHmacSHA256";
/**
* 비밀번호를 해싱하고 솔트와 함께 반환
* @param password 해싱할 비밀번호
* @return 솔트와 해시를 합친 byte 배열
*/
public static byte[] hashPassword(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
// 랜덤 솔트 생성
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt);
// 비밀번호 해싱
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
salt,
ITERATIONS,
HASH_LENGTH
);
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
byte[] hash = factory.generateSecret(spec).getEncoded();
// 솔트와 해시 합치기
byte[] combined = new byte[salt.length + hash.length];
System.arraycopy(salt, 0, combined, 0, salt.length);
System.arraycopy(hash, 0, combined, salt.length, hash.length);
return combined;
}
/**
* 저장된 해시값과 비밀번호가 일치하는지 검증
* @param password 검증할 비밀번호
* @param storedHash 저장된 해시 (솔트 + 해시)
* @return 일치 여부
*/
public static boolean verifyPassword(String password, byte[] storedHash)
throws NoSuchAlgorithmException, InvalidKeySpecException {
// 저장된 해시에서 솔트 추출
byte[] salt = new byte[SALT_LENGTH];
System.arraycopy(storedHash, 0, salt, 0, salt.length);
// 저장된 해시값 추출
byte[] hash = new byte[storedHash.length - SALT_LENGTH];
System.arraycopy(storedHash, SALT_LENGTH, hash, 0, hash.length);
// 입력된 비밀번호를 같은 솔트로 해싱
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
salt,
ITERATIONS,
HASH_LENGTH
);
SecretKeyFactory factory = SecretKeyFactory.getInstance(ALGORITHM);
byte[] testHash = factory.generateSecret(spec).getEncoded();
// 해시값 비교
return Arrays.equals(hash, testHash);
}
/**
* Base64로 인코딩된 문자열로 변환
*/
public static String toBase64(byte[] data) {
return Base64.getEncoder().encodeToString(data);
}
/**
* Base64 문자열을 byte 배열로 디코딩
*/
public static byte[] fromBase64(String data) {
return Base64.getDecoder().decode(data);
}
// 사용 예시
public static void main(String[] args) {
try {
// 비밀번호 해싱
String password = "myPassword123";
byte[] hashedPassword = hashPassword(password);
String base64Hash = toBase64(hashedPassword);
System.out.println("Hashed password: " + base64Hash);
// 비밀번호 검증
boolean isValid = verifyPassword(password, hashedPassword);
System.out.println("Password is valid: " + isValid);
// 잘못된 비밀번호 검증
boolean isInvalid = verifyPassword("wrongPassword", hashedPassword);
System.out.println("Wrong password is valid: " + isInvalid);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
}
}
String password = "myPassword123";
byte[] hashedPassword = PasswordHasher.hashPassword(password);
String base64Hash = PasswordHasher.toBase64(hashedPassword);
// 데이터베이스에 base64Hash 저장
// 나중에 비밀번호 검증시
boolean isValid = PasswordHasher.verifyPassword(
inputPassword,
PasswordHasher.fromBase64(storedHash)
);
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class AESExample {
private static final String ALGORITHM = "AES";
public static String encrypt(String value, String key) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedBytes = cipher.doFinal(value.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public static String decrypt(String encrypted, String key) throws Exception {
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encrypted));
return new String(decryptedBytes);
}
}
import java.security.*;
import javax.crypto.Cipher;
public class RSAExample {
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
return generator.generateKeyPair();
}
public static byte[] encrypt(String message, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(message.getBytes());
}
public static String decrypt(byte[] encrypted, PrivateKey privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decrypted = cipher.doFinal(encrypted);
return new String(decrypted);
}
}
import java.security.*;
public class DigitalSignatureExample {
public static byte[] createDigitalSignature(String message, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(message.getBytes());
return signature.sign();
}
public static boolean verifyDigitalSignature(String message, byte[] signedMessage, PublicKey publicKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(message.getBytes());
return signature.verify(signedMessage);
}
}
import javax.net.ssl.*;
import java.security.cert.X509Certificate;
public class SSLExample {
public static void setupSSLContext() throws Exception {
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
sslContext.init(null, trustManagers, new SecureRandom());
SSLContext.setDefault(sslContext);
}
}
PKI(Public Key Infrastructure) 시스템과 SSL/TLS 동작 과정을 자세히 설명해드리겠습니다.
예: Verisign, GlobalSign, Let's Encrypt 등
이러한 PKI 시스템과 SSL/TLS 프로토콜은 현대 인터넷 보안의 근간이 되며, 특히 전자상거래, 온라인 뱅킹 등 보안이 중요한 서비스에서 필수적으로 사용됩니다.