01. 암호화/복호화 정의
- 암호화: 우리가 사용하는 평범한 문장(평문)을 의미할 수 없는 암호문으로 변환하는 것
- 복호화: 암호문을 평문으로 되돌리는 것
02. 암호 알고리즘: 암호화/복호화를 할 때 사용하는 알고리즘
- 양방향 암호 알고리즘: 대칭 키 암호 알고리즘, 비대칭 키 암호 알고리즘
- 단방향 암호 알고리즘: 해시 알고리즘
03. 암호화 키/복호화 키
- 암호화 키: 암호화를 위한 키
- 복호화 키: 복호화를 위한 키
04. 대칭 키 암호 알고리즘 vs 비대칭 키 암호 알고리즘
- 대칭 키 암호 알고리즘: 암호화 키 == 복호화 키
- 비대칭 키 암호 알고리즘: 암호화 키 != 복호화 키
05. 대칭 키 암호 알고리즘 종류
*권고 여부: 암호화 강도를 고려해 전문가들은 최소 128비트 이상의 알고리즘 사용을 권고함*
*AES: 예제로 사용할 알고리즘*
06. 대칭 키 암호 알고리즘 구현하기
(1) 대칭 키 암호 알고리즘 - 암호화
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
public class AESEncryption {
private SecretKeySpec secretKey;
private byte[] initialVector;
// 대칭 키 암호화를 위한 메소드
public String encrypt(String plainText, String secretString) throws Exception{
byte[] sha256 = null;
byte[] cipherText = null;
//secretString 에 대한 해시 값 생성
sha256 = MessageDigest.getInstance("SHA-256")
.digest(secretString.getBytes(StandardCharsets.UTF_8));
// 해시 값을 16바이트 배열로 나누어 저장
sha256 = Arrays.copyOf(sha256, 16);
// 해시 값과 AES 알고리즘을 이용하여 비밀 키 생성
secretKey = new SecretKeySpec(sha256, "AES");
// 첫 번째 블록 암호화를 위해 난수값을 생성하며 초기화 벡터 생성
initialVector = new byte[16];
SecureRandom random = new SecureRandom();
random.nextBytes(initialVector);
/* 암호화 객체 생성
* - 암호 알고리즘: ASE
* - 블록 암호화 운영 모드: CBC
* - 패딩: PKCS5Padding
* */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 암호화 모드, 대칭 키, 초기화 벡터 값을 입력하여 암호화 객체 초기화
cipher.init(Cipher.ENCRYPT_MODE,
secretKey,
new IvParameterSpec(initialVector));
// 데이터 암호화 수행
cipherText = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
// Base64 로 인코딩하여 암호문 반환
return Base64.getEncoder().encodeToString(cipherText);
}
06-1. 운영 모드: 우리가 사용하는 암호화 방식은 데이터를 블록으로 나눔, 이를 위한 운영 모드로는
(1) ECB(Electronic Code Book)
- 데이터를 블록으로 나눈 후 각각 암호화
- 동일한 블록에 동일한 암호문 생성
(2) CBC(Cipher-Block Chaining)
- 데이터를 블록으로 나눈 후 체인을 만들어 암호화
- 동일한 블록에 다른 암호문 생성
*체인: 이전 블록의 암호화 결과를 다음 블록의 암호화에 사용하는 방식
*보안 강도: CBC > ECB
*위의 코드에서는 CBC를 사용, CBC는 가장 첫 번째 블록의 경우, 이전 블록이 없기 때문에 초기화 벡터를 랜덤함수를 통해 생성하여 사용함*
06-2. 패딩 방식(Public-Key Cryptography Standard, PKCS)
- 블록 암호화 방식을 이용하려면 블록의 길이는 일정해야 함
- 블록의 크기가 16바이트가 되지 않으면 크기를 맞춰주기 위한 임의의 값 추가
- PKCS#5: 패딩 값 최대 8 바이트
- PKCS#7: 패딩 값 최대 256바이트
*요즘 사용하는 알고리즘은 블록 크기가 16바이트 이상이기 대문에 패딩 값을 많이 채워주는 PKCS#&을 사용
*하지만 JAVA에서 위 패딩을 사용할 경우, 예외(NoSuchAlgorithmException)이 발생,
*PKCS#5를 사용하더라도 내부적으로는 PKCS#7로 정상 작동함
06-3. Base64형식으로 인코딩
- 암호문은 이진 데이터로 생성
- 이진 데이터는 네트워크 통신 과정에서 신호왜곡, 비트 오류 등의 손실 위험이 존재
- 데이터베이스 관점: 이진 데이터보다 문자열 데이터 처리가 더 용이
- 다른 애플리케이션과 연동하거나 데이터 입출력 시 Base64로 표현하는 규약이 존재
(2) 대칭 키 암호 알고리즘 - 복호화
// 대칭 키 복호화 함수
public String decrypt(String cipherText, SecretKeySpec secretKey) throws Exception{
byte[] plainText = null;
// 암호화 객체 생성
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// 암호화 모드, 대칭 키, 초기화 벡터 값을 입력하여 암호화 객체 초기화
cipher.init(Cipher.DECRYPT_MODE,
secretKey,
new IvParameterSpec(initialVector));
// 데이터 복호화 수행
plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));
// 바이트 형식으로 복호화된 데이터를 문자열 형식으로 변환하여 반환
return new String(plainText);
}
// 대칭 키 및 암호 알고리즘 조회
public SecretKeySpec getSecretKey(){
return secretKey;
}
}
(3) 대칭 키 암호 알고리즘 - 결과
- plain Text로 123456을 입력하였을 때
- 대칭 키 AES로 암호화 하면 encrypted와 같이 결과가 나오고
- 이 결과를 다시 복호화하면 decrypted와 같이 원래의 plain Text가 나오는 것을 볼 수 있음
'JAVA 심화' 카테고리의 다른 글
[JAVA] 심화 - 단방향 암호화 기법 (2) (0) | 2024.12.30 |
---|---|
[JAVA] 심화 - 단방향 암호화 기법 (1) (0) | 2024.12.30 |
[JAVA] 심화 - 양방향 암호화 기법, 비대칭 키 암호 알고리즘 (2) (1) | 2024.12.30 |